list_groups
Retrieve Signal groups with group IDs, names, members, and admins. Use this to obtain group_id for sending messages.
Instructions
List Signal groups with group_id, name, description, members, and admin lists, sorted alphabetically.
Read-only with no side effects. Queries signal-cli when available; falls back to the local desktop database (without group_id). Use this to obtain group_id values needed by send_message. Use list_chats instead for a combined view of both direct and group chats.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Case-insensitive substring to filter group names. Empty string returns all groups. | |
| limit | No | Maximum number of groups to return, between 1 and 200. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/mcp_signal/server.py:204-238 (handler)Main MCP tool handler for 'list_groups'. Decorated with @mcp.tool(). Accepts optional 'query' (case-insensitive substring filter) and 'limit' (1-200). Attempts signal_cli.list_groups() first, falls back to reader.list_local_groups() on SignalCLIError.
@mcp.tool() def list_groups( query: Annotated[ str, Field( description=( "Case-insensitive substring to filter group" " names. Empty string returns all groups." ), ), ] = "", limit: Annotated[ int, Field( description=( "Maximum number of groups to return," " between 1 and 200." ), ), ] = 50, ) -> list[dict[str, Any]]: """List Signal groups with group_id, name, description, members, and admin lists, sorted alphabetically. Read-only with no side effects. Queries signal-cli when available; falls back to the local desktop database (without group_id). Use this to obtain group_id values needed by send_message. Use list_chats instead for a combined view of both direct and group chats. """ limit = min(max(limit, 1), _MAX_LIMIT) try: return signal_cli.list_groups(query=query, limit=limit) except SignalCLIError: return reader.list_local_groups(query=query, limit=limit) - src/mcp_signal/signal_cli.py:100-120 (helper)Signal CLI back-end implementation. Calls signal-cli RPC method 'listGroups', filters by case-insensitive query substring, and returns dicts with group_id, name, description, members, admins, is_member, is_blocked. Sorted alphabetically by name.
def list_groups(self, *, query: str = "", limit: int = 50) -> list[dict[str, Any]]: groups = self._rpc("listGroups") or [] query_lower = query.strip().lower() rows = [] for group in groups: name = group.get("name") or "" if query_lower and query_lower not in name.lower(): continue rows.append( { "group_id": group.get("id"), "name": name, "description": group.get("description") or "", "members": group.get("members") or [], "admins": group.get("admins") or [], "is_member": group.get("isMember", True), "is_blocked": group.get("isBlocked", False), } ) rows.sort(key=lambda item: item["name"].lower()) return rows[:limit] - src/mcp_signal/reader.py:160-164 (helper)Fallback implementation using the local desktop database. Filters list_chats() for groups only, sets group_id to None, and returns up to 'limit' results.
def list_local_groups(self, query: str = "", limit: int = 50) -> list[dict[str, Any]]: groups = [chat for chat in self.list_chats(query=query, limit=10_000) if chat["is_group"]] for group in groups: group["group_id"] = None return groups[:limit] - src/mcp_signal/server.py:206-224 (schema)Pydantic Field annotations for 'query' (optional str with description) and 'limit' (optional int with description, default 50). Used as Annotated type hints on the handler parameters.
query: Annotated[ str, Field( description=( "Case-insensitive substring to filter group" " names. Empty string returns all groups." ), ), ] = "", limit: Annotated[ int, Field( description=( "Maximum number of groups to return," " between 1 and 200." ), ), ] = 50, ) -> list[dict[str, Any]]: