Borrowing it
Nothing to install: this file belongs to zulip/zulipmcp. Take a copy, put it at the same path in your own repository, and replace the rules that are about this project with yours.
curl -O https://raw.githubusercontent.com/zulip/zulipmcp/main/CLAUDE.mdgit clone --depth 1 https://github.com/zulip/zulipmcpWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/instructions/zulip/zulipmcp/claude-md)<a href="https://agentmods.dev/instructions/zulip/zulipmcp/claude-md"><img src="https://agentmods.dev/badge/instructions/zulip/zulipmcp/claude-md/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/instructions/zulip/zulipmcp/claude-md"><img src="https://agentmods.dev/badge/instructions/zulip/zulipmcp/claude-md.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00922 | $0.00922 |
| Opus 5.5 | $0.00369 | $0.00369 |
| Sonnet 5.5 | $0.00184 | $0.00184 |
| Haiku 4.5 | $0.00092 | $0.00092 |
Grade B, and why
zulipmcp CLAUDE.md scanned grade B with 1 finding against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2mo ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Reads MCP configurationmediumAgent snooping
mcp.json carries server URLs and auth tokens; reading it lets a mod discover and abuse other integrations.
- **Codex MCP config is not `.mcp.json` native.** The listener translates `.mcp.json` into Codex `-c mcp_servers...` overrides. Keep secrets in env/header fields; env refs in command/args/cwd/url must fail closed to avoi Copies of this mod
1 near-identical copy found in the catalogue:
- zulipmcp CLAUDE.md — 100% identical, 35 lines differ
How it starts
The opening of the file, as written. The whole thing — 35 lines — stays where its author put it; the contents beside it link to each section on GitHub.
zulipmcp
Public open-source repo. All code, commits, and PRs are visible to the world.
Rules
- Nothing WindBorne-specific. No internal URLs, emails, Zulip instances, or infra references.
- No internal context in PRs, commits, or comments.
- Elegant, general code. Type hints everywhere. Minimal dependencies.
Architecture
core.py— Zulip API wrappers. No MCP dependency. Returns Python objects.mcp.py— MCP tool layer +SessionState. Thin wrappers overcore.py. Hooks system lives here.agent_backends.py— Claude/Codex/OpenCode command builders for the listener. No Zulip API dependency.hermes_plugin/zulip/— Native Hermes gateway transport. It does not use MCP session state.
Separation is load-bearing: core.py must stay MCP-agnostic so it works as a standalone library import.
Gotchas
listen()is async, everything else is sync. It runsget_events()in a thread executor to interleave MCP keepalive pings. Don't make other tools async — FastMCP handles sync tools fine.- Event queue narrow does NOT filter reactions.
is_dismiss_reaction()receives reactions from all streams — it fetches the reacted-on message to verify stream/topic. Don't remove that check. _sessionis module-level singleton. One session per process. Don't add multi-session — MCP is one-client-per-server.reply()checks for missed messages before sending. Thelast_seen_message_idbookkeeping is subtle — trace it carefully before changing.- Send tools enforce
MAX_MESSAGE_LENGTH. Zulip silently truncates over-limit messages and still reports success — the guard returns an error to the caller instead. It measures the normalized form (postnormalize_zulip_markdown()), since normalization can grow content. Override withZULIP_MAX_MESSAGE_LENGTHfor non-default realm caps. - Two dismiss-check paths exist intentionally.
listen()catches via events,reply()via REST poll. Both needed — user might react during tool execution (not listening). - Interrupt-file reads must go through
_consume_interrupt_file(). It claims via atomic rename before reading, so a writer replacing the file mid-consume can't have its content deleted unread — and it decodes witherrors="replace"so a bad-bytes file can't wedge every future poll. Don't inline a read+delete elsewhere. - Private stream security is asymmetric on purpose. Unset
BOT_ALLOWED_PRIVATE_STREAMS= no access (default-deny). UnsetBOT_ALLOWED_WRITE_STREAMS= all writes allowed (backwards-compat). Don't "fix" the asymmetry. configure()must be called beforerun_server().run_server()may auto-init a session that reads hook state.- Codex MCP config is not
.mcp.jsonnative. The listener translates.mcp.jsoninto Codex-c mcp_servers...overrides. Keep secrets in env/header fields; env refs in command/args/cwd/url must fail closed to avoid argv leaks. - OpenCode MCP config is not
.mcp.jsonnative. The listener translates.mcp.jsoninto inline JSON viaOPENCODE_CONFIG_CONTENT. Header values are embedded directly (no env-var indirection like Codex). Env refs in command/args/url are rejected. core.pysend paths (send_message/send_direct_message/edit_message) rewrite markdown vianormalize_zulip_markdown(). Blank lines are injected before tables and bold/link combos Zulip breaks on are rewritten. Fenced/indented code is exempt from both fixes; inline code spans are exempt only for the bold/link rewrite. The Hermes gateway adapter sends via the raw client and is NOT normalized.ZULIPMCP_MARKDOWN_AUTOFIX=0disables all of it.remove_reaction()needs explicitreaction_typefor custom emoji. Zulip's DELETE reactions endpoint defaultsreaction_typetounicode_emoji— custom emoji removals fail silently without it. The listen indicator caches_listen_reaction_typealongside_listen_emoji; always pass both when removing.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 2mo ago First seen · 35 lines · 922 tokens per session scan B 0d401fa52144
zulipmcp CLAUDE.md is an instructions file published in the GitHub repository zulip/zulipmcp (25 stars, last pushed 3mo ago), licensed Apache-2.0. It adds 922 tokens to every session, about $0.0037 per session on Opus 5.5. A static security scan graded it B with 1 finding (reads mcp configuration). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.
zulipmcp CLAUDE.md compared with instructions from other repositories
| Mod | Type | Stars | Last push | Licence | Scan | Tokens | Works with |
|---|---|---|---|---|---|---|---|
| zulipmcp CLAUDE.mdzulip/zulipmcp | Instructions file | 25 | 3mo ago | Apache-2.0 | B | 922 | Claude Code |
| vscode buildNext.instructions.mdmicrosoft/vscode | Instructions file | 195k | yesterday | MIT | A | 9,719 | GitHub Copilot |
| next.js AGENTS.mdvercel/next.js | Instructions file | 143k | yesterday | MIT | A | 7,461 | Codex, OpenCode |
| langchain AGENTS.mdlangchain-ai/langchain | Instructions file | 149k | yesterday | MIT | A | 4,680 | Codex, OpenCode |
| vscode oss-third-party-notices.instructions.mdmicrosoft/vscode | Instructions file | 195k | yesterday | MIT | A | 5,516 | GitHub Copilot |
| vscode copilot-instructions.mdmicrosoft/vscode | Instructions file | 195k | yesterday | MIT | A | 3,093 | GitHub Copilot |
| deepseek-harness AGENTS.mddeepseek-ai/deepseek-harness | Instructions file | 274k | 2d ago | MIT | A | 4,313 | Codex, OpenCode |