zulip-mcp
The zulip-mcp server provides a read-only interface to browse and search Zulip chat data — no creating, modifying, or deleting anything.
Verify connection:
get_own_profileto confirm authentication and view your user info (ID, email, full name)Browse streams:
list_streams(all visible streams) orlist_subscriptions(only your subscribed streams)Look up stream ID:
get_stream_idby stream name (needed for topic listing)Explore topics:
list_topicsto list conversation threads in a stream, ordered most recent firstFetch messages:
get_messageswith flexible filters (stream, topic, sender email, full-text search) and anchor-based paginationGet a single message:
get_messageby numeric message IDList all users:
list_usersto get a directory of the entire organizationLook up a user:
get_userby numeric ID or email address
The server is designed with a hardened, secure architecture: no code execution, no filesystem access, no telemetry, local credential handling, and stdio-only communication.
Provides read-only access to Zulip chats, allowing listing of streams, topics, messages, and users, with search capabilities.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@zulip-mcpList all streams I'm subscribed to"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
zulip-mcp
Minimal, secure, read-only MCP server for reading Zulip chats from Claude Code (or any MCP client). Browse streams, topics, messages, and users — nothing can be created, modified, or deleted.
Why this exists
A security review of an existing Zulip MCP server surfaced serious issues
(eval()-based remote code execution, arbitrary local file read/write, SSRF).
This is a clean, minimal alternative built around a strict read-only,
no-code-execution design. See Security.
Related MCP server: mcp-infra-readonly
Requirements
Install
Clone the repo:
git clone https://github.com/shreyan-gupta/zulip-mcp.git
cd zulip-mcpThen install with either uv or pip:
# Option A — uv (recommended; also installs the right Python)
uv sync
# Option B — pip + venv
python3 -m venv .venv
.venv/bin/pip install -e .Get your Zulip API key
Open your Zulip instance (e.g.
https://your-org.zulipchat.com).Avatar → Personal settings → Account & privacy.
Under API key, click Manage your API key and copy it.
Add to Claude Code
Run this from inside the cloned repo ($(pwd) expands to its absolute path):
# Option A — uv
claude mcp add zulip \
-e ZULIP_EMAIL=you@example.com \
-e ZULIP_API_KEY=your-api-key \
-e ZULIP_SITE=https://your-org.zulipchat.com \
-- uv run --directory "$(pwd)" zulip-mcp
# Option B — venv entry point
claude mcp add zulip \
-e ZULIP_EMAIL=you@example.com \
-e ZULIP_API_KEY=your-api-key \
-e ZULIP_SITE=https://your-org.zulipchat.com \
-- "$(pwd)/.venv/bin/zulip-mcp"Restart Claude Code, then try:
> List the streams I'm subscribed to
> Show messages in #engineering about "sync redesign"
> Summarize my last week of messages in #generalTip: ask it to call get_own_profile first to confirm the connection works.
Tools
Tool | Description |
| Verify connection, see authenticated user info |
| List channels you're subscribed to |
| List all visible streams in the org |
| Look up a stream's ID by name |
| List topics in a stream |
| Fetch messages with stream/topic/sender/search |
| Fetch a single message by ID |
| Get user profile by ID or email |
| List all users in the org |
get_messages supports anchor-based pagination and combines filters (stream,
topic, sender, full-text search) into a single query.
Security
This server is designed to be safe by construction:
Read-only — cannot create, modify, or delete any Zulip data.
No code execution — no
eval(),exec(),subprocess, or dynamic imports.No filesystem access — tools never read or write local files.
No telemetry — every network request goes exclusively to your Zulip instance.
Stdio only — no HTTP listener, no open ports.
Credentials stay local — read from env vars, never logged or returned in output.
Configuration
Configuration is via environment variables only (no .env auto-loading):
Environment Variable | Required | Description |
| Yes | Your Zulip login email or bot email |
| Yes | API key from Zulip settings |
| Yes | Base URL of your Zulip instance |
Development
uv sync --extra dev # or: pip install -e ".[dev]"
ruff check .
pytestThe test suite is offline — it never contacts a real Zulip server.
License
Available Tools
9 toolsget_messageA
Fetch a single message by its ID.
Use this when you have a specific message ID and want its full content, or when following up on a message reference from another tool's output.
Args: message_id: The numeric message ID. include_html: If True, return HTML. If False (default), raw Markdown.
Returns: JSON object with the full message details.
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes | ||
| include_html | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does not disclose authorization needs, side effects, or performance implications, but as a basic fetch, the core behavior is transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the main action in the first sentence, then succinct usage guidelines, parameter details, and return info. Every sentence serves a purpose with no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 parameters, output schema present), the description fully covers purpose, usage, parameters, and return format. It is complete for an agent to select and invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description adds full meaning: message_id is 'numeric message ID', include_html explains True returns HTML, False returns Markdown. This adds significant value beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description starts with 'Fetch a single message by its ID', clearly stating the verb and resource. The tool name 'get_message' is well-described, and it is distinct from sibling tools like 'get_messages' (plural) and others.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Description provides explicit when-to-use: 'when you have a specific message ID and want its full content, or when following up on a message reference.' It lacks explicit when-not-use or alternatives, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_messagesA
Fetch messages from Zulip with flexible filtering.
This is the primary tool for reading chat history. Combine filters to narrow down results — e.g., stream + topic to get a specific conversation, or sender + search to find specific messages from a person.
Pagination: Results are anchored at a point and fetch messages before/after it. To paginate through history:
First call: anchor="newest", num_before=100
Next call: anchor=, num_before=100
Repeat until found_oldest is true.
Args: stream: Filter by stream/channel name (e.g., "eng-resharding"). topic: Filter by topic/thread name within a stream. sender: Filter by sender email (e.g., "shreyan@nearone.org"). search: Full-text search query across message content. anchor: Reference point — a message ID (as string) or "newest", "oldest", "first_unread". Defaults to "newest". num_before: Number of messages before the anchor. Max 5000. Defaults to 100. num_after: Number of messages after the anchor. Max 5000. Defaults to 0. include_html: If True, return HTML-rendered content. If False (default), return raw Markdown source — better for analysis.
Returns: JSON object with keys: - messages: list of message objects (id, sender, content, timestamp, etc.) - found_newest: whether there are no newer messages matching the filter - found_oldest: whether there are no older messages matching the filter - anchor: the anchor message ID used
| Name | Required | Description | Default |
|---|---|---|---|
| topic | No | ||
| anchor | No | newest | |
| search | No | ||
| sender | No | ||
| stream | No | ||
| num_after | No | ||
| num_before | No | ||
| include_html | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses pagination behavior (anchor, num_before/num_after, found_newest/oldest), default values, and the effect of include_html on output format. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with an overview, usage tips, pagination instructions, and a parameter list. It is thorough but not overly verbose; could be slightly more concise, but every sentence serves a purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity (8 parameters, no required ones, output schema exists), the description covers all aspects: filter parameters, pagination, return keys. It is complete enough for an agent to invoke correctly without ambiguity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, requiring the description to fully explain parameters. It does so thoroughly: allowed anchor values, defaults, max limits for num_before/num_after, and the difference between include_html options. This significantly adds value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with 'Fetch messages from Zulip with flexible filtering,' using a specific verb and resource. It distinguishes itself from the sibling tool 'get_message' (singular) by indicating it retrieves multiple messages with filtering capabilities.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states it is the 'primary tool for reading chat history' and provides usage examples (e.g., combining filters). Detailed pagination steps are given, making it clear how to iterate through results. The distinction from 'get_message' is implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_own_profileA
Get the authenticated user's own profile.
Use this to verify the connection is working and to see who is authenticated. This is the first tool to call when setting up.
Returns: JSON object with user profile: user_id, email, full_name, etc.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It mentions the return format (JSON object with user_id, email, etc.), adding some value, but does not disclose other behavioral traits like authentication requirements, side effects, or rate limits. The return description is helpful but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise at 5 lines, front-loaded with the purpose, followed by usage guidance and return details. Every sentence adds value without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (0 params, output schema exists), the description adequately covers purpose, usage, and return format. It is complete for an agent to understand when and how to use the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and schema coverage is 100% (trivially). Per guidelines, a no-parameter tool baseline is 4. The description adds no parameter information because none exists.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Get the authenticated user's own profile', using a specific verb and resource. It distinguishes from siblings like get_user and get_message by focusing on the authenticated user's profile.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly advises using this tool to verify connection and to see who is authenticated, including 'This is the first tool to call when setting up.' While it does not explicitly mention when not to use it, the guidance is clear and context-rich for a simple tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_stream_idA
Look up a stream's numeric ID by its name.
Use this when you know a stream's name but need its ID for other API calls (e.g., list_topics requires a stream_id).
Args: stream_name: Exact name of the stream (case-sensitive).
Returns: JSON object with the stream_id.
| Name | Required | Description | Default |
|---|---|---|---|
| stream_name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description must disclose behavior. It mentions case-sensitivity and that return is a JSON object with stream_id. However, it does not cover error behavior, rate limits, or potential side effects. The description is adequate for a simple lookup tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise with three short paragraphs, each serving a purpose: purpose, usage guidance, and parameter/return details. No unnecessary words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists (though not shown), the description summarizes the return object. It does not specify behavior on failure (e.g., if stream not found), but for a straightforward lookup, it is nearly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 0% description coverage, so the description must add meaning. It does by stating that stream_name requires an exact, case-sensitive name. This goes beyond the schema's minimal type and title.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('look up') and the resource ('stream's numeric ID by its name'), distinguishing it from sibling tools like list_streams which list all streams. It is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when to use the tool: when you know a stream's name but need its ID for other API calls, with an example (list_topics). It does not explicitly mention when not to use, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_userA
Get a user's profile by their numeric ID or email address.
Args: identifier: Either a numeric user ID (e.g., "12345") or an email address (e.g., "alice@example.com").
Returns: JSON object with user profile details.
| Name | Required | Description | Default |
|---|---|---|---|
| identifier | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description states the return type (JSON object with user profile details) but does not disclose error behavior, permission requirements, or rate limits. As a simple read operation without annotations, it is adequate but lacks full transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise, with a front-loaded purpose sentence followed by clear Args and Returns sections. Every word adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's low complexity (one parameter, output schema exists), the description covers the essential information. It could benefit from a brief note on error handling or authentication, but it is largely complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage for the sole parameter 'identifier', the description compensates by explaining it can be a numeric ID or email, with examples. This adds meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'get' and resource 'user's profile', and specifies the two types of identifiers (numeric ID or email). This differentiates it from sibling tools like list_users (list all users) and get_own_profile (own profile).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implicitly indicates when to use the tool: when you need a specific user's profile and have their identifier. It doesn't explicitly state when not to use it, but the sibling names provide context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_streamsA
List all visible Zulip streams (channels).
Use this to discover what streams/channels exist in the organization. Returns stream names, IDs, descriptions, and subscriber counts.
Args: include_public: Include public streams. Defaults to True. include_subscribed: Include streams you're subscribed to. Defaults to True. exclude_archived: Exclude archived streams. Defaults to True.
Returns: JSON list of streams with their metadata.
| Name | Required | Description | Default |
|---|---|---|---|
| include_public | No | ||
| exclude_archived | No | ||
| include_subscribed | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It states the tool returns stream names, IDs, descriptions, and subscriber counts. However, it does not disclose authentication needs, rate limits, or what 'visible' entails regarding permissions. It is moderately transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise with two short paragraphs plus structured Args and Returns sections. It is front-loaded with the main purpose. No unnecessary words; every part serves a purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simplicity (3 boolean params, no nesting, output schema exists), the description covers the tool's purpose, parameters, and return format adequately. It is complete for a list tool, though could mention that an output schema provides more detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description compensates by listing each parameter with its default value in the Args section. This adds meaningful context beyond the raw schema, though it could explain the semantics more deeply (e.g., what 'include_public' means exactly).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'List all visible Zulip streams (channels).' and adds 'Use this to discover what streams/channels exist in the organization.' This provides a specific verb and resource, distinguishing it from sibling tools like get_stream_id or list_subscriptions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description says 'Use this to discover what streams/channels exist.' It gives context for use but does not specify when NOT to use it or mention alternatives like list_subscriptions (which lists subscriptions, not streams). No explicit exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_subscriptionsA
List streams (channels) you are subscribed to.
Use this to see which streams the authenticated user can access. More focused than list_streams — only shows your subscriptions.
Returns: JSON list of subscribed streams with names and IDs.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must cover behavioral traits. It implies a read operation and mentions the return format, but does not disclose authentication requirements, rate limits, or potential side effects beyond what is obvious.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short, front-loaded, and contains no extraneous words. Every sentence serves a clear purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given zero parameters, an existing output schema, and the simplicity of the tool, the description covers purpose, usage, and return format adequately. No gaps are evident.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters and 100% description coverage, so baseline is 4. The description does not add parameter information as none exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists streams the user is subscribed to, using a specific verb and resource. It differentiates from sibling tool list_streams by noting it is more focused and only shows subscriptions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description says when to use this tool ('to see which streams the authenticated user can access') and compares it to list_streams as an alternative. It lacks explicit exclusion criteria but provides clear context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_topicsA
List topics (threads) in a stream, most recent first.
Use this to discover what conversations exist in a stream before fetching messages. Each topic is like a thread/subject line.
Args: stream_id: The numeric ID of the stream. Use get_stream_id to look this up.
Returns: JSON list of topics with names and last message IDs.
| Name | Required | Description | Default |
|---|---|---|---|
| stream_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description bears full responsibility. It discloses the output format (JSON list of topics with names and last message IDs) and sorting order (most recent first). It does not mention edge cases like empty lists or permissions, but for a read-only list tool it is sufficient.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise with no superfluous words. It front-loads the purpose, then gives usage guidance, parameter details, and return format in a logical order.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having an output schema, the description still explains the return format. With only one required parameter and clear documentation, it is fully complete for a simple list tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description compensates by explaining the stream_id parameter as 'The numeric ID of the stream' and references get_stream_id for lookup. This adds meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it lists topics (threads) in a stream, most recent first. It differentiates from sibling tools like get_message and get_messages by stating it discovers conversations before fetching messages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Use this to discover what conversations exist in a stream before fetching messages.' Provides clear context for when to use it, though no exclusions are mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_usersA
List all users in the Zulip organization.
Returns all active and deactivated users. Use this to find user IDs or email addresses for filtering messages.
Returns: JSON list of user objects with basic profile info.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It states the tool returns all active and deactivated users in a JSON list with basic profile info, which is transparent about the output. However, it does not disclose any behavioral traits like pagination, rate limits, or performance implications, which could be relevant for a large user list.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short sentences, front-loaded with the core purpose. Every sentence adds value: the first states what it does, the second specifies scope, the third gives return format and usage. No unnecessary words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool is a simple list with no parameters and an output schema exists, the description is complete. It mentions the return format and provides a concrete use case. The complexity is low, and the description adequately covers what an agent needs to know to use the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters and coverage is 100%, so the description adds no parameter details. Following the calibration, a baseline of 4 is appropriate when there are no parameters, as the description does not need to provide parameter semantics beyond what the schema offers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it lists all users in the Zulip organization, including active and deactivated. It distinguishes its purpose from siblings like get_user (single user) and other list tools by specifying it returns the full list and is used for finding user IDs or email addresses.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly gives a use case: 'Use this to find user IDs or email addresses for filtering messages.' This tells the agent when to use it. However, it does not explicitly mention when not to use it or name alternatives among siblings, though the use case implies differentiation.
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.
9 tool updates
v0.1.0- First observed
get_message - First observed
get_messages - First observed
get_own_profile - First observed
get_stream_id - First observed
get_user - First observed
list_streams - First observed
list_subscriptions - First observed
list_topics - First observed
list_users
TDQS
Scored across 9 tools
Each tool has a clearly distinct purpose: get_message vs get_messages differ in cardinality, get_user vs get_own_profile differ in target, list_streams vs list_subscriptions differ in scope. No overlap or ambiguity.
All tool names follow a consistent verb_noun pattern using snake_case (e.g., get_message, list_streams). There are no deviations or mixed conventions.
9 tools is a reasonable number for a Zulip MCP server focused on reading data. Each tool serves a distinct function without being excessive or insufficient for the apparent scope.
The server is read-only, missing core write operations such as sending messages, creating streams, or subscribing. This is a significant gap for a chat platform, limiting agent capability.
Maintenance
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
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
Read-only MCP server for RZ AI Labs — query its services, workshops, and contact info.
Read-only MCP server for turva.dev, an agent-readiness audit and advisory service.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA read-only MCP server that enables Claude Code to access MySQL databases, allowing safe querying with SELECT, SHOW, DESCRIBE, and EXPLAIN.32MIT
- FlicenseNot gradedqualityBmaintenanceA read-only MCP server that gives Claude Code secure, non-invasive access to infrastructure logs, service status, metrics, Ansible facts, and Docker state via SSH, with a strict command allowlist and no write operations.-
- AlicenseNot gradedqualityBmaintenanceA read-only MCP server that gives Claude unified access to multiple Gmail and Microsoft 365 accounts, enabling email search, reading, and listing through one connection.126MIT
- AlicenseNot gradedqualityBmaintenanceA read-only MCP server that gives Claude safe access to Kubernetes clusters, enabling listing, describing, and monitoring resources without mutation risks and with secret masking.1MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/shreyan-gupta/zulip-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server