MCP server for accessing and searching Signal messenger data
The Signal MCP server has three READ_ONLY tools with basic descriptions and schemas visible in the source code. However, significant issues limit quality: (1) Parameter redundancy: all three tools repeat the same 6 parameters (source_dir, password, key, chats, include_empty, include_disappearing) across every function signature. This violates single responsibility and composition patterns, these are configuration concerns that should be handled once at initialization, not repeated for every call. (2) Descriptions are present but generic; they largely mirror the docstring template without explaining WHEN to use each tool or what distinguishes them from each other. (3) Input schemas are visible and properly typed (Path, str, bool, Optional[int]), but parameters lack actionable constraints, no ranges for offset/limit, no explanation of the 'chats' CSV format. (4) No output schema documentation, return types are declared (List[Dict[str, Any]]) but field names and structure are undocumented, forcing LLMs to infer. (5) No error handling guidance, if a chat_name doesn't exist or source_dir is invalid, the tools fail silently or return empty results with no recovery hints. (6) The tools lack clear composition, it's not obvious to an LLM when to use signal_list_chats vs signal_get_chat_messages, or whether signal_search_chat requires calling signal_list_chats first.
Get Signal messages from a specific chat by name. Args: chat_name (str): The name of the chat to retrieve messages from. limit (Optional[int]): Maximum number of messages to return. offset (int): Number of messages to skip before starting to collect results. source_dir (Path): Path to the Signal data directory. password (Optional[str]): Password for encrypted data, if applicable. key (Optional[str]): Key for encrypted data, if applicable. chats (str): Comma-separated list of chat IDs to filter. include_empty (bool): Whether to include empty chats. include_disappearing (bool): Whether to include disappearing messages. Returns: List[Dict[str, Any]]: A list of dictionaries containing messages from the specified Signal chat.
List all Signal chats with their details. Args: source_dir (Path): Path to the Signal data directory. password (Optional[str]): Password for encrypted data, if applicable. key (Optional[str]): Key for encrypted data, if applicable. chats (str): Comma-separated list of chat IDs to filter. include_empty (bool): Whether to include empty chats. include_disappearing (bool): Whether to include disappearing messages. Returns: List[Dict[str, Any]]: A list of dictionaries containing Signal chat details.
Search for specific text within a Signal chat. Args: chat_name (str): The name of the chat to search within. query (str): The text to search for in messages. limit (Optional[int]): Maximum number of matching messages to return. source_dir (Path): Path to the Signal data directory. password (Optional[str]): Password for encrypted data, if applicable. key (Optional[str]): Key for encrypted data, if applicable. chats (str): Comma-separated list of chat IDs to filter. include_empty (bool): Whether to include empty chats. include_disappearing (bool): Whether to include disappearing messages. Returns: List[Dict[str, Any]]: A list of messages that match the search query.
Repeated configuration parameters across all tools. Every tool redefines source_dir, password, key, chats, include_empty, include_disappearing. This violates single responsibility, these are environment/initialization concerns, not per-call parameters.
No output schema documentation. Return type is List[Dict[str, Any]] with no specification of field names, types, or structure. LLMs cannot plan downstream operations without knowing what keys to extract (e.g., does signal_list_chats return 'chat_id' or 'id'? 'name' or 'contact_name'?).
Descriptions are generic and do not guide LLM selection. All three tools have similar descriptions that largely repeat their function signature. No explanation of when to use signal_list_chats vs signal_get_chat_messages, or when signal_search_chat is preferable to iterating through messages manually.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-21 | F | 44 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 42 | - | v1 |
No input constraints documented for offset, limit, chats, and other parameters. 'chats (str): Comma-separated list of chat IDs to filter' does not explain the format or what happens if the format is wrong. 'offset (int)' lacks min/max bounds. Unconstrained inputs invite invalid LLM values.
No error recovery guidance. If source_dir is invalid, password is wrong, or chat_name does not exist, tools fail silently or return empty results. No error messages tell the LLM what to do next (retry with different params, call a discovery tool first, etc.).
Parameter naming ambiguity. 'chats (str)' is unclear, is it a filter? An ID? A name? Comparing to baseline patterns, this should be 'chat_ids' or 'chat_id_filter' to clarify type and intent. Parameter names like 'source_dir' expose implementation details (file system paths); 'data_directory' or 'signal_data_path' would be clearer.