Avoid per-agent stdio contention on the sqlite index, sort FTS by rank with created tie-break, and add mm_search_tag for dated #plan/#report substring search. Co-authored-by: Cursor <cursoragent@cursor.com>
8.0 KiB
name, description
| name | description |
|---|---|
| mattermost-search | Search Mattermost export dumps via mattermost-search MCP (mm_search_mcp.py): message text, attachment names, attachment text content, filters by user/channel/team/date. Use when the user asks to find messages, posts, or files in Mattermost exports, mattermost-dl results, or the local sqlite index; or about daily #plan/#report in System/HW (see everyday.md). Requires MCP server mattermost-search. Index bypass (no_index, regex, CLI, grep) needs explicit user permission. |
Mattermost Search (MCP)
Search local Mattermost JSON exports produced by mattermost-dl.py. Always use MCP
tools (mm_search, mm_search_tag, mm_resolve_user, mm_search_users,
mm_user_directory_refresh, mm_search_index_status) as the default path.
Mandatory rules
Поиск в обход индекса и MCP — только с явного разрешения пользователя.
Не делать самостоятельно, пока пользователь явно не попросил:
Всё про ежедневные планы или отчёты смотри: everyday.md. Там и формат описан, и каналы.
My username: sergey.marinkevich. Resolve others via mm_resolve_user(ref="Цисык") →
vladislav.tsisyk (needs user directory — see below).
| Обход | Примеры |
|---|---|
| Индекс | no_index=true, regex=true (сканирует JSON), прямое чтение/grep по results/ |
| MCP | запуск mm_search.py, python mm_search.py …, любой shell вместо MCP tools |
Разрешено без спроса: mm_search с индексом (used_index: true) — обычный
search_mode="message", file_name, file_content.
Если индекс недоступен или нужен regex/scan: остановиться, сообщить пользователю
(нет db_exists, нужен mm_index.py, или требуется медленный обход JSON) и дождаться
явного «да» перед no_index, regex, CLI или чтением файлов экспорта.
Prerequisites
mattermost-searchMCP server connected (mm_search,mm_search_index_statusvisible).- Export JSON under
results/(orMM_SEARCH_ROOT). - SQLite index
mattermost_index.sqlite(orMM_SEARCH_DB) for fast search and required for attachment search. Build/update:python mm_index.py.
Prefer one shared HTTP instance (not stdio per agent). User systemd unit:
mm-search-mcp.service → http://127.0.0.1:8766/mcp. In ~/.cursor/mcp.json:
"mattermost-search": { "url": "http://127.0.0.1:8766/mcp" }
Server env (HTTP service / stdio env):
| Variable | Default |
|---|---|
MM_SEARCH_ROOT |
results |
MM_SEARCH_DB |
mattermost_index.sqlite |
MM_CONFIG_PATH |
config.json (for mm_user_directory_refresh(from_api=true)) |
MM_MCP_TRANSPORT |
stdio (http for shared server) |
MM_MCP_HOST / MM_MCP_PORT |
127.0.0.1 / 8766 |
Quick start
mm_search_index_status()without paramters — confirmdb_exists,root_exists,json_files.- Pick search_mode (see table below).
mm_search(query=…, …)with filters; keeplimitsmall (10–50) unless the user needs all hits.- Read
matches[].post.message; for attachments alsomatches[].attachment.
Tools
| Need | Tool |
|---|---|
| Search messages / attachments | mm_search(query, …) |
#plan / #report in a date range |
mm_search_tag(keyword, after, before, …) |
| Resolve display name → username | mm_resolve_user(ref) |
| Search users by name | mm_search_users(query) |
| Refresh user directory | mm_user_directory_refresh(from_api=true) |
| Check index & export layout | mm_search_index_status(db, root) |
User directory is stored in the sqlite DB (users table). Sources: users.json in export
root (written by mattermost-dl.py), Mattermost API (from_api=true), and distinct
usernames from indexed posts.
Choose search_mode
| Goal | search_mode |
Notes |
|---|---|---|
| Text in post body | message (default) |
Uses FTS index; JSON scan only with user permission |
| Attachment filename | file_name |
Index required; no regex |
| Text inside attachment | file_content |
Index required; UTF-8 text files only |
| Regex in message | message + regex=true |
User permission required — scans JSON, skips index |
Tag #plan / #report by date |
use mm_search_tag |
Required after/before; substring #keyword; newest first |
mm_search parameters
| Param | Role |
|---|---|
query |
Search string (or regex pattern) |
user |
Exact username filter |
channel |
Exact display_name or name |
team |
Exact team name |
after / before |
YYYY-MM-DD or ISO datetime |
limit |
Max matches (apply early — large exports) |
ignore_case |
Default: on for substring, off for regex |
no_index |
Force JSON file scan — user permission required |
output |
json (default) or human (CLI-style lines) |
show_file |
Prefix file:idx: in human output |
Response shape (output=json)
{
"count": 2,
"used_index": true,
"search_mode": "message",
"root": "results",
"db": "mattermost_index.sqlite",
"matches": [
{
"file": "results/20260605/user/channel.json",
"channel": "general",
"team": "myteam",
"post": {
"id": "…",
"idx": 42,
"created": "2026-01-15T10:00:00Z",
"username": "alice",
"message": "…",
"files": ["path/to/file.pdf"]
},
"attachment": {
"filename": "doc.txt",
"path": "…",
"is_text": true
}
}
]
}
attachment is present only for file_name / file_content hits.
Common workflows
Find what someone wrote about a topic
mm_search(query="deploy rollback", user="alice", after="2026-01-01", limit=20)
Find posts in a channel
mm_search(query="incident", channel="alerts", limit=30)
Resolve user, then search their posts
mm_user_directory_refresh(from_api=true)
mm_resolve_user(ref="Цисык")
mm_search(query="#report", user="vladislav.tsisyk", channel="System/HW", limit=30)
Check somebody report (when username is known)
mm_search(query="#report", user="ivan.pavlov", channel="System/HW", limit=30)
Find attachment by name
mm_search(query="report.pdf", search_mode="file_name", limit=10)
Regex over raw JSON (no index) — только после явного разрешения пользователя
mm_search(query="ERROR-\\d+", regex=true, no_index=true, limit=50)
Human-readable listing for the user
mm_search(query="standup", output="human", show_file=true, limit=15)
Pitfalls
file_name/file_content+regex=true→ error.- Attachment search without index → error; run
mm_index.pyfirst. channel/user/teamare exact matches, not substring — resolve display names withmm_resolve_userfirst.- User directory empty → run
mm_user_directory_refresh(from_api=true)or re-export withmattermost-dl.py(writesusers.json). - Token budget: prefer
limit, narrowafter/before, then widen if empty. - If
count=0with index: broadenquery, drop filters, suggestmm_index.py— не переключаться наno_index/regex/ CLI без явного разрешения.
Related CLI
Использовать только по явной просьбе пользователя (обход MCP):
| CLI | MCP equivalent |
|---|---|
mm_search.py QUERY |
mm_search(query=QUERY) |
--file-name |
search_mode="file_name" |
--file-content |
search_mode="file_content" |
--regex |
regex=true (permission required) |
--no-index |
no_index=true (permission required) |
mm_index.py |
not in MCP — предложить пользователю, не запускать самому |