Signal MCP
signal-mcp links to your Signal account as a device and gives an AI assistant (or CLI) a private, local, searchable memory of your chats plus 80+ tools to read, search, and act on them.
Messaging — send/receive DMs, groups, attachments, stickers, stories, and notes to self; supports @mentions, quotes, link previews, view-once, voice notes, and Signal text formatting.
Message management — edit, react, pin/unpin, remote-delete your own (or any message as group admin), send read receipts and typing indicators.
Search & history — full-text (FTS5) search with sender/date filters, paginated conversation history, unread retrieval, store stats, and JSON/CSV export.
Contacts & profiles — list/search contacts, set nicknames and notes, block/unblock/remove, update your own profile and avatar.
Groups — create, join, update (members, admins, labels, bans, permissions, invite links), leave, or terminate; set disappearing-message timers.
Polls — create, vote on, and terminate polls in DMs or groups.
Scheduling — queue messages for later, list/cancel them, and run due sends.
Devices & security — list/add/remove/rename linked devices, inspect and trust identity keys (safety numbers), set/remove registration-lock PIN, change number, manage accounts.
Stickers — list, install, retrieve, upload, and send stickers from installed packs.
History import — full import or incremental sync from Signal Desktop.
Automation — webhooks for incoming messages and a background capture service.
Privacy & safety — 100% local SQLite store, read-only mode (
SIGNAL_MCP_READONLY=1), send-root allow-list to prevent file exfiltration, and explicit confirmation for destructive actions.
Allows reading, searching, and sending Signal messages, managing contacts, groups, and conversation history through a local Signal CLI daemon.
signal-mcp
Give your AI assistant a memory for Signal — privately, on your own machine.
Searchable message history · 80+ tools · groups, polls, mentions, labels · read-only mode · 100% local
signal-mcp is an MCP server and CLI built on signal-cli, the community-made, unofficial Signal client. It links to your existing Signal account as a device, keeps every message in a local database you can search, and lets an AI assistant like Claude read, search and — if you allow it — act on your chats. No cloud service, no third party: your messages stay on your computer.
You What did the coach say about Sunday, and did anyone offer to bring the jerseys?
Claude Daniel (coach): meet 10:15 at the hall, kickoff 11:00, ten boys confirmed.
Elena and Mikko both replied — they'll bring the jerseys. Nothing needs
an answer from you except confirming your son is coming.
You Tell the group we'll be there, and tag the coach.
Claude Sent to "U12 Team": "@Daniel we'll be there at 10:15 👍"Illustrative example with made-up names.
Independent project — not affiliated with Signal. signal-mcp is not made, endorsed or supported by Signal Messenger or the Signal Foundation. It talks to Signal through signal-cli, an unofficial third-party client that you link to your account as an extra device (like Signal Desktop). Signal does not provide support for unofficial clients, and using one is at your own risk — see Signal's Terms of Service.
The same data from your terminal — this is real signal-mcp output on a demo database:
Why it exists
I built signal-mcp for a very ordinary reason: I'm a parent in my kids' football-team group chats and wanted my assistant to keep up with them — kickoff times, who's bringing the jerseys, which tag to set. I use it every day, against my own real Signal account, which is why safety (read-only mode, no file exfiltration, nothing leaving the machine) is built in rather than bolted on.
Related MCP server: mcp-signal
Why you want this
signal-cli is excellent at the Signal protocol and deliberately minimal everywhere else. signal-mcp adds the parts you need to actually use your messages:
A memory. signal-cli delivers a message and forgets it. signal-mcp stores everything — including messages you sent from your phone — in local SQLite, and can import your whole Signal Desktop history.
Search that works. Full-text search across all chats, filterable by sender and date range.
Real conversations. Paginated threads, unread counts, last-message previews — and names instead of
+12025551234, even for group members who aren't in your contacts.Everything Signal shows you. @mentions (resolved to names), polls, pins, link previews, quotes, voice notes, stickers, group member labels, join requests — nothing signal-cli reports is thrown away.
Full control when you want it. Send, reply, react, edit, delete, manage groups, schedule messages, set your profile — with a read-only switch for when you don't.
Zero babysitting. The daemon starts itself and restarts if it crashes; an optional background service captures messages while Claude isn't running;
signal-mcp doctortells you what's wrong if something is.
Quick start
brew install signal-cli # Linux: see Setup below
signal-cli link --name "MyMac" # scan the QR code: Signal → Settings → Linked Devices
uv tool install signal-mcp
claude mcp add signal -- signal-mcp serveNeeds Python 3.12+, signal-cli 0.13+ and a Signal account on your phone. Restart Claude Code and ask "check my Signal messages". Works with any MCP client (Claude Code and Claude Desktop are what it is developed and tested with) — config snippets are in Setup.
What you can ask
Catch up | "What did I miss while I was offline?" · "Summarize the parents' group since Monday." |
Find | "Find every message about the invoice." · "What did Anna say about the trip last week?" |
Act | "Reply to Marco that Thursday works." · "Remind the team at 9:00 tomorrow." · "Create a poll for Friday's dinner." |
Groups | "Who's waiting to join the group?" · "Set my label in the football group to my son's name." |
Housekeeping | "Export my chat with Mom as CSV." · "Who hasn't messaged me in a month?" · "Delete that message for everyone." |
Prefer the terminal? Everything is also a command — signal-mcp send, search, conversations, export, … (CLI usage). The CLI and MCP server share one store and one daemon.
Private and safe by design
100% local. Messages live in SQLite on your disk; the daemon listens on localhost only. There is no signal-mcp cloud. (The only things that leave your machine are what you send through Signal itself and an optional webhook you configure.)
Read-only mode.
SIGNAL_MCP_READONLY=1hides and blocks every tool that sends, edits, deletes or changes settings — for assistants you don't fully trust with your account. See Step 7.No file exfiltration. Anything that uploads a local file (attachments, avatars, link-preview images, sticker packs) only reads from an allow-list of folders (
SIGNAL_MCP_SEND_ROOTS; default: your attachments folder, Downloads, Desktop, Documents) and never from hidden files or folders — so a message that says "send me~/.ssh/id_ed25519" can't talk an assistant into it.Irreversible means confirmed. Clearing the local store or terminating a group requires an explicit
confirm.Careful with secrets. The Signal Desktop import decrypts into a private (
0700) folder, passes the key over stdin rather than the command line, and cleans up even when interrupted.Honest caveat. Messages from other people are untrusted text that an AI will read. Read-only mode (or just not granting write access) is the strongest defence against a hostile message trying to steer your assistant.
What's new
1.40 closes the gap with signal-cli: incoming @mentions, polls, pins, previews and quotes are now captured; group member labels, bans, permissions and join requests; contact nicknames and notes; link previews, voice notes and stories on the sending side; and a fix that finally copies received attachments. See the changelog.
Setup
Step 1 — Install signal-cli
signal-mcp is a front-end for signal-cli, an independent, unofficial client that handles the Signal protocol.
macOS
brew install signal-cliLinux
Download the latest release from signal-cli releases, extract it, and put the signal-cli binary on your $PATH.
Step 2 — Link your Signal account
signal-cli needs to be linked to your existing Signal account (the same way you'd add a linked device in Signal mobile).
signal-cli link --name "MyMac"This prints a QR code in your terminal. On your phone:
Signal → Settings → Linked Devices → + → scan the QR code
Once scanned, signal-cli is linked and ready.
Step 3 — Install signal-mcp
With uv (recommended):
uv tool install signal-mcpWith pip or pipx:
pip install signal-mcp
# or
pipx install signal-mcpFrom source:
git clone https://github.com/googlarz/signal-mcp
cd signal-mcp
uv tool install .Verify it works:
signal-mcp status
# → Account : +1234567890
# → Daemon : stopped (port 7583)Step 4 — Connect to Claude Code
claude mcp add signal -- signal-mcp serveRestart Claude Code. Signal tools appear automatically — ask Claude "check my Signal messages" to confirm.
Claude Code — global (~/.claude.json):
{
"mcpServers": {
"signal": {
"command": "uvx",
"args": ["signal-mcp", "serve"]
}
}
}Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"signal": {
"command": "uvx",
"args": ["signal-mcp", "serve"]
}
}
}Claude Desktop uses a restricted PATH —
uvxresolves the tool without needingsignal-mcpon your shell's PATH.
Per-project (.mcp.json):
{
"mcpServers": {
"signal": {
"command": "uv",
"args": ["run", "--directory", "/path/to/signal-mcp", "signal-mcp", "serve"]
}
}
}Step 5 — (Optional) Import Signal Desktop history
If you use Signal Desktop, import your full message history in one command.
macOS
brew install sqlcipher # required for decryption
signal-mcp import-desktop # macOS will prompt for Keychain access — click AllowLinux (Debian/Ubuntu shown — use your distribution's packages elsewhere)
sudo apt install sqlcipher libsecret-tools # decryption + keyring lookup (secret-tool)
signal-mcp import-desktop # your keyring must be unlockedStep 6 — (Optional) Enable background message capture
signal-cli only delivers messages when polled. Install the background service so nothing is missed:
signal-mcp install-service # starts on login, works on macOS and LinuxStep 7 — (Optional) Read-only mode
Set SIGNAL_MCP_READONLY=1 in the environment to restrict the server to read-only
tools (listing, searching, and exporting existing local/remote state). Tools that
send, edit, delete, or otherwise mutate your Signal account — messages, contacts,
groups, devices, and settings — are hidden from tool listings and rejected if
called directly. Useful when connecting an AI client you don't fully trust with
write access to your real Signal account.
Troubleshooting
Start with signal-mcp doctor — it checks signal-cli, your linked account, the daemon, and message capture, and says which one is broken.
Symptom | Cause and fix |
| A bug in signal-cli 0.14.8 ( |
"Unknown sender" / bare numbers in a group | Names come from your contacts, then Signal profiles (also for non-contacts), then Signal Desktop. Someone with none of these stays a number — |
| Needs |
Messages missing while Claude wasn't running | Install the background service: |
Attachment has no local file | Received files are copied to |
MCP Tools
Messaging
Tool | Description |
| Send a text message to a contact (by number, or by Signal |
| Send a text message to a group. Supports quoted replies, |
| Send a file or image to a contact. Supports captions, view-once and |
| Send a file or image to a group. Supports captions, view-once and |
| Save a note to yourself (Signal's saved messages). |
| Poll for new incoming messages and delivery receipts. Optional |
| Receive by calling signal-cli directly (no daemon) — for when the background service isn't running. Optional |
| Get messages not yet marked as read from local store. |
| Edit a previously sent message (DM or group). Updates local store. Incoming edits from contacts also update the stored copy in-place. |
| Remote-delete (unsend) a sent DM. |
| Remote-delete a sent group message. |
| React to a message with an emoji (DM or group). Set |
| Pin a message in a DM or group conversation. |
| Unpin a message in a DM or group conversation. |
| Group admin: delete any message in a group you administer. |
| Send (or stop) a typing indicator in a chat or group. |
| Post an image or video to your Signal story, optionally to a group story. |
| Mark messages as read. Also updates local store. |
| Send a sticker to a contact. |
| Send a sticker to a group. |
Configuration
Tool | Description |
| Toggle read receipts, typing indicators, link previews, or sealed sender indicators. |
Sticker Packs
Tool | Description |
| List all installed sticker packs with |
| Install a sticker pack from a |
| Retrieve a single sticker image as base64. |
| Upload and publish a sticker pack from a local manifest.json or zip. Returns the signal.art URL. |
Contacts
Tool | Description |
| All contacts with names and numbers. Supports optional |
| Get profile info for a contact. |
| Set a local display name for a contact. |
| Block a contact. |
| Unblock a contact. |
| Remove a contact from the local list. |
| Update your own name, about text, or avatar. |
| Get the Signal number this server is running as. |
Message output now carries everything signal-cli reports for incoming messages, when present:
mentions(withbody_resolved, the text with@namein place of the placeholder),text_styles,previews,quote(author and text),voice_note,sticker, polls (poll_create/poll_vote/poll_terminate), pins, story replies and shared contacts. Remote and admin deletes flag the stored message (remote_deleted,admin_deleted_by) instead of erasing your local copy.
Groups
Tool | Description |
| All groups with members and metadata: member labels ( |
| Create a new Signal group. |
| Join a group via invite link. |
| Rename, add/remove members, promote/demote admins, set expiry timer, avatar, ban/unban, reset invite link, group permissions, and your own member label ( |
| Leave a group. A sole admin must name a successor ( |
| Permanently end a group for every member. Irreversible; requires |
History & Search
Tool | Description |
| All conversations ordered by most recent message. |
| Message history with a contact or group. Supports |
| Full-text search (FTS5) across all stored messages. Supports |
| Total message count, oldest and newest message dates. |
| Mark one or more stored messages as unread. |
| Check whether phone numbers are registered Signal users. |
| Request sync of messages/contacts/groups from your primary device. |
| Push your contacts list to all linked devices. |
| Accept or decline a message request from an unknown sender. |
Security & Devices
Tool | Description |
| List identity keys and trust levels (safety numbers). |
| Trust a contact's identity key after verifying their safety number. |
| List all devices linked to your account. |
| Link a new device using a device link URI. |
| Unlink a device by ID. |
| Rename a linked device. |
| List all Signal accounts configured in signal-cli on this machine. |
| Update account settings: device name, discoverability, number sharing, username. |
| Set the Signal registration lock PIN. |
| Remove the Signal registration lock PIN. |
| Retrieve the avatar image for a contact or group as base64. |
Polls
Tool | Description |
| Create a poll in a group conversation. |
| Cast a vote on an existing poll. |
| End a poll and prevent further votes. |
Disappearing Messages
Tool | Description |
| Set or disable disappearing messages for any DM or group. |
Scheduling
Tool | Description |
| Queue a message for later ( |
| List queued messages ( |
| Cancel a pending scheduled message by id. |
| Send everything that is due now. Nothing sends scheduled messages by itself — call this tool, or run |
Webhooks
Tool | Description |
| Set (or clear) a URL that receives a JSON |
| Show the configured webhook URL. |
Data & Import
Tool | Description |
| One-time full import of all historical messages from Signal Desktop. Requires sqlcipher. |
| Incremental sync from Signal Desktop — imports only messages newer than the last sync. Fast on repeat calls. First call behaves like |
| List all locally downloaded attachments (photos, files received via Signal). |
| Get details about a downloaded attachment by filename; if it is not in the local attachments folder it is fetched from signal-cli by attachment id. |
| Delete ALL locally stored messages (requires |
| Delete locally stored messages for one contact or group. |
| Export stored messages as JSON or CSV. Supports |
CLI Usage
# Status & daemon
signal-mcp status # account + daemon info
signal-mcp doctor # onboarding smoke test: signal-cli, account, daemon, receive health
signal-mcp daemon # start daemon in foreground
signal-mcp stop # stop the daemon
# Send & receive
signal-mcp send +1234567890 "Hello!"
signal-mcp send +1234567890 "**Heads up** — *lunch at 1*" --format
signal-mcp send-group <group_id> "Hey!"
signal-mcp send-group <group_id> "**Kickoff** is at *11:00*" --format # bold + italic
signal-mcp note "Remember to buy milk" # save a note to yourself
signal-mcp receive # poll once
signal-mcp receive --watch # keep watching (saves to store)
# Edit
signal-mcp edit +1234567890 <timestamp> "corrected text"
signal-mcp edit <group_id> <timestamp> "corrected text"
# React / delete / block
signal-mcp react +1234567890 <timestamp> +1234567890 👍
signal-mcp delete +1234567890 <timestamp> # unsend a message you sent
signal-mcp block +1234567890 # and: signal-mcp unblock ...
# Pin / unpin / admin-delete messages
signal-mcp pin +1234567890 <timestamp> +1234567890
signal-mcp unpin +1234567890 <timestamp> +1234567890
signal-mcp admin-delete <group_id> <timestamp> +1234567890
# Devices
signal-mcp update-device <device_id> "My Laptop"
# Contacts & groups
signal-mcp contacts
signal-mcp contacts --json
signal-mcp find-contact anna # add --all-recipients to include non-contacts (e.g. group members)
signal-mcp groups
signal-mcp group-label <group_id> "Anna" # set YOUR OWN member label in a group
signal-mcp conversations # list all chats with unread count + last message
# History & search
signal-mcp history +1234567890
signal-mcp history +1234567890 --limit 20
signal-mcp history +1234567890 --limit 20 --offset 20 # page 2
signal-mcp history +1234567890 --since 2024-01-01
signal-mcp search "keyword"
signal-mcp search "keyword" --sender +1234567890 # restrict to one contact
signal-mcp search "keyword" --limit 20
signal-mcp search "invoice" --since 2024-01-01 --until 2024-02-01
signal-mcp store-stats
# Export
signal-mcp export # all messages as JSON to stdout
signal-mcp export messages.json # save to file
signal-mcp export messages.csv --format csv # CSV format
signal-mcp export --recipient +1234567890 --format csv # one conversation
signal-mcp export --since 2024-01-01 # messages from date
# Scheduled messages
signal-mcp schedule-send +1234567890 "Happy birthday!" --at "2027-01-01 09:00"
signal-mcp scheduled # list; cancel with: signal-mcp cancel-scheduled <id>
signal-mcp run-scheduled # send whatever is due now
# Stories & webhooks
signal-mcp story photo.jpg
signal-mcp set-webhook http://localhost:8080/signal # run without a URL to clear
signal-mcp get-webhook
# Housekeeping
signal-mcp prune --days 180 # delete local messages older than 180 days
# Signal Desktop import — one-time full import
signal-mcp import-desktop
signal-mcp sync-desktop # incremental: only new messages since last sync
# Background service (macOS LaunchAgent or Linux systemd)
signal-mcp install-service # auto-starts on login, captures all messages
signal-mcp uninstall-service
# MCP server (for Claude Code)
signal-mcp serveGetting full message history
signal-cli only delivers new messages — it has no history API. Two ways to get history:
Going forward (captures everything from now on):
signal-mcp install-service # background watcher, auto-starts on loginRetroactively (imports everything from Signal Desktop):
signal-mcp import-desktop # macOS prompts for Keychain access; Linux needs an unlocked keyringRun both for complete coverage.
Architecture
┌─────────────────────────────────┐
│ signal-cli daemon (:7583) │
│ Signal protocol / libsignal │
└──────────┬──────────────┬────────┘
│ sends/receives│
┌──────────▼──────────┐ │ (when no service)
│ background service │ │
│ LaunchAgent/systemd │ │
└──────────┬──────────┘ │
│ writes │
┌──────────▼──────────────▼────────┐
│ SQLite store │
│ ~/.local/share/signal-mcp/ │
│ messages.db (FTS5 indexed) │
└────────────────┬─────────────────┘
│ reads/writes
┌─────────────────┼─────────────────┐
│ │ │
┌──────────▼──────┐ ┌────────▼───────┐ ┌──────▼──────────┐
│ Claude Code / │ │ signal-mcp │ │ signal-mcp CLI │
│ Claude Desktop │ │ serve (MCP) │ │ (terminal) │
│ (asks Claude) │ └────────────────┘ └─────────────────┘
└─────────────────┘How it works:
get_unread is the primary "check for new messages" tool. If the background service is installed, it reads straight from the store (the service keeps it up to date). Otherwise it polls signal-cli first (debounced to once every 30 seconds) and includes a _warning suggesting signal-mcp install-service. list_conversations is a pure store read — fast, no polling.
The daemon starts automatically on first use. Attachments are saved to ~/Downloads/signal-attachments/.
signal-cli Coverage
signal-mcp wraps the signal-cli JSON-RPC daemon. Here's what is and isn't covered:
Covered (81 tools)
signal-cli command | signal-mcp tool |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Plus tools with no direct signal-cli equivalent: get_conversation, search_messages, list_conversations, store_stats, import_desktop, sync_desktop, export_messages, mark_as_unread, clear_local_store, delete_local_messages, prune_store.
Not covered
These commands are deliberately excluded — either not feasible to implement as MCP tools, or consciously left out (see the reason for each):
signal-cli command | Why |
| Voice/video calls require WebRTC and an active media stack — not feasible via MCP |
| One-time account setup; must be done before installing signal-mcp |
| Irreversibly destroys all local Signal data; too destructive to expose |
| Only forwards a MobileCoin receipt produced by an external wallet; signal-mcp cannot create or verify one |
Development
git clone https://github.com/googlarz/signal-mcp
cd signal-mcp
uv sync --dev
uv run pytest
uv run pytest --cov --cov-report=term-missing573 tests, 100% line coverage across all modules. All tests are fully mocked — no signal-cli installation or Signal account required to run them.
See CONTRIBUTING.md for how to add new tools.
License
MIT — see LICENSE.
Available Tools
81 toolsadd_deviceA
Link a new device (e.g. Signal Desktop or another signal-cli) to your account. uri (required): the device-link URI (sgnl://linkdevice?...) shown by the new device as a QR code or printed by 'signal-cli link'. Only works when signal-mcp is the account's primary device — fails with 'This command doesn't work on linked devices' if signal-mcp was set up via signal-cli link. Also fails on a malformed or expired link or when the account already has the maximum number of linked devices. The linked device gets full access to the account; never use a URI from an untrusted source. Returns status 'device linked'; confirm with list_devices, undo with remove_device.
| Name | Required | Description | Default |
|---|---|---|---|
| uri | Yes | Device link URI (sgnl://linkdevice?...) from the new device's QR code or signal-cli link output |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the generic safety profile (readOnly=false, destructive=false, openWorld=true, idempotent=false). The description adds what annotations cannot: the exact error string returned when run on a linked device, the three failure modes, the fact that the linked device gains full account access, and an explicit security warning never to use an untrusted URI.
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?
Front-loaded with the action, then prerequisites, failure modes, and cleanup path in a tight sequence; every sentence carries operational information. It is on the denser side for a one-parameter tool, but no sentence is filler.
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?
For a single-parameter, no-output-schema mutation tool, it covers everything an agent needs: prerequisite state, error conditions, security caveat, the return status string ('device linked'), and the follow-up/undo tools.
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 coverage is 100% and the single uri parameter is fully described in the schema, so the description's mention of 'the device-link URI (sgnl://linkdevice?...) shown as a QR code or printed by signal-cli link' mostly reinforces existing schema text. Baseline 3 applies when the schema carries the semantics.
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?
States a specific verb and resource — 'Link a new device ... to your account' — with an example of what a device is. It is immediately distinguishable from siblings like list_devices, update_device, and remove_device.
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 the precondition (only works when signal-mcp is the primary device), the failure conditions (linked-device setup, malformed/expired link, device limit), and routes the agent to alternatives: confirm with list_devices, undo with remove_device.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_sticker_packAIdempotent
Install an existing sticker pack on this Signal account from its signal.art link. uri (required): https://signal.art/addstickers/#pack_id=&pack_key=; both pack_id and pack_key are needed. Installing the same pack again has no further effect. Returns {status: 'installed', pack_id} with pack_id parsed from the uri, ready for send_sticker, send_group_sticker or get_sticker; call list_sticker_packs to see the sticker ids and emoji in it. Use upload_sticker_pack instead to publish a new pack of your own images.
| Name | Required | Description | Default |
|---|---|---|---|
| uri | Yes | Sticker pack URL (https://signal.art/addstickers/#pack_id=...&pack_key=...) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=true, openWorldHint=true), but the description adds concrete meaning: the exact return shape {status: 'installed', pack_id}, that pack_id is parsed from the uri, and that re-installation is a no-op. It stops short of mentioning any auth or rate-limit considerations, but the added behavioral context is real.
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?
Front-loaded with the core action, then the input constraint, then the return value and routing. Every sentence carries information, though the inline uri format with angle-bracket placeholders makes the middle clause slightly dense.
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?
With no output schema, the description compensates by documenting the return payload and the parsed pack_id, and it names the downstream tools (send_sticker, send_group_sticker, get_sticker) plus the inspection tool (list_sticker_packs). Nothing needed to invoke this correctly is missing.
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 coverage is 100% with a single uri parameter, but the description goes beyond the schema by spelling out the required fragment structure (pack_id=<hex>&pack_key=<hex>) and stressing that both pack_id and pack_key must be present — a validation detail the schema's terse description does not convey.
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?
States a specific verb ('Install') plus resource ('an existing sticker pack on this Signal account') and the required input format (signal.art link). It also explicitly distinguishes itself from upload_sticker_pack, which publishes new packs, so an agent can disambiguate without reading either schema.
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?
Gives the when (install an existing pack via signal.art uri), the when-not/alternative (use upload_sticker_pack to publish your own images), and the repeat-call behavior (installing the same pack again has no further effect). It also routes to list_sticker_packs for inspecting pack contents.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
admin_delete_messageADestructiveIdempotent
As a group admin, delete any member's message in that group for all participants. For your own messages use delete_group_message (group) or delete_message (DM); for local-only removal delete_local_messages. Requires admin rights — check is_admin in list_groups. group_id: from list_groups; target_author: E.164 number of the message's sender; target_timestamp: its ms timestamp (message id in get_conversation). Irreversible; contacts Signal's servers; the local store copy is kept. Returns {status: 'message deleted by admin'}.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | Yes | Group ID where the message was sent (get from list_groups) | |
| target_author | Yes | Phone number of the user who sent the message | |
| target_timestamp | Yes | Timestamp of the message to delete (from get_conversation) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and openWorldHint=true, but the description adds context annotations cannot express: 'Irreversible; contacts Signal's servers; the local store copy is kept.' That local-store nuance is non-obvious and material to the caller's decision.
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?
Purpose is front-loaded, followed by alternatives, prerequisites, and parameter sourcing in tight clauses. Every sentence carries operational value with no filler.
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?
Even without an output schema, the description documents the return shape (returns {status: 'message deleted by admin'}), the permissions requirement, the server/local split, and sibling routing. Nothing an agent needs to invoke it correctly is missing.
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 coverage is 100%, so the baseline is 3, but the description adds format detail beyond the schema — E.164 numbering for target_author and that target_timestamp is the message id 'in ms' from get_conversation. These sharpen how to supply the values.
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?
States a specific verb ('delete'), resource ('any member's message'), and scope ('in that group for all participants'), and explicitly distinguishes itself from delete_group_message, delete_message, and delete_local_messages. An agent can identify this tool without opening any sibling schema.
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?
Names each alternative and the condition that selects it (own messages vs. member messages, group vs. DM, server vs. local removal), and states the prerequisite plus how to verify it ('check is_admin in list_groups'). This is explicit when-to-use/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
block_contactAIdempotent
Block a contact so you stop receiving their messages and calls. number (required, E.164). Only works when signal-mcp is the account's primary device — fails with 'This command doesn't work on linked devices' if signal-mcp was set up via signal-cli link. The contact is not notified. The blocked list is synced to your linked devices, and if you share no group with them your profile key is rotated so they lose access to your profile updates. Message history is kept. Blocking an already blocked contact is a no-op. Reversible with unblock_contact. To only delete the local contact entry without blocking, use remove_contact. Returns status 'blocked' and number.
| Name | Required | Description | Default |
|---|---|---|---|
| number | Yes | Phone number to block (E.164 format, e.g. +1234567890) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say destructiveHint=false and idempotentHint=true; the description adds substantial context beyond them: the primary-device precondition and error string, that the contact is not notified, that the blocked list syncs to linked devices, that the profile key is rotated when no shared group exists, that message history is kept, and that re-blocking is a no-op (consistent with idempotentHint).
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?
Front-loaded with purpose, then constraints, side effects and the alternative tool. Despite being a dense paragraph, every sentence carries distinct, decision-relevant information and none is filler.
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?
With no output schema, the description compensates by stating the return value ('status \'blocked\' and number'). Combined with preconditions, side effects, reversibility and the no-op case, an agent has everything needed to call this 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 100% and the single parameter already documents E.164 format with an example. The description restates 'number (required, E.164)' but adds no new syntax or constraint beyond the schema, so the baseline 3 applies.
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 leads with a specific verb and resource plus the user-visible effect: 'Block a contact so you stop receiving their messages and calls.' It clearly distinguishes itself from sibling tools it is often confused with (remove_contact deletes the local entry only; unblock_contact reverses this).
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?
Explicit when-it-works precondition ('Only works when signal-mcp is the account's primary device'), the exact failure message on linked devices, and a named alternative ('To only delete the local contact entry without blocking, use remove_contact'). Reversibility with unblock_contact is also stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cancel_scheduled_messageADestructiveIdempotent
Cancel one pending scheduled message so it will never be sent. job_id (required, integer): the id from schedule_message or list_scheduled_messages. Local only; the job stays in the list with status 'cancelled' and cannot be re-activated (schedule it again instead). Returns {status: 'cancelled', job_id}, or an error if no pending job has that id (already sent, failed, cancelled or unknown).
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | Scheduled message job ID from list_scheduled_messages |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing that the operation is local-only, that the job remains in the list with status 'cancelled', that it is irreversible without rescheduling, and that an error is returned when no pending job matches (already sent, failed, cancelled, or unknown). That is exactly the mutation/irreversibility context an agent needs.
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?
One dense paragraph that front-loads the action and outcome, then layers id provenance, behavioral caveats, and return shape. No sentence is filler.
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?
With annotations covering the safety profile (destructive, idempotent, non-read-only) and no output schema, the description supplies the missing return shape and failure modes. Nothing an agent needs to invoke this correctly is absent.
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 coverage is already 100%, so the baseline is 3, but the description adds value by naming both source tools for the id and tying id validity to the error case. It still does not clarify whether the id is globally unique or per-account, so it stops short of 5.
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?
States a specific verb and resource ('Cancel one pending scheduled message') plus the outcome ('so it will never be sent'), which cleanly separates it from siblings like delete_message, schedule_message, and run_scheduled_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?
Names the tools that produce the required id (schedule_message, list_scheduled_messages) and routes the agent away from re-activation ('cannot be re-activated; schedule it again instead'). It gives clear context but never states when this should be preferred over other message-removal tools such as delete_message.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
clear_local_storeADestructiveIdempotent
Delete ALL messages and attachment records from signal-mcp's local database. confirm (boolean, required) must be exactly true, otherwise nothing is deleted and an error is returned. Local only: nothing is deleted from Signal, your phone or other devices, and downloaded attachment files on disk are left in place. Irreversible except by re-importing (import_desktop) or receiving again. Returns {deleted: count, status: 'cleared'}. Use delete_local_messages to clear one conversation, prune_store to drop only old messages; delete_message unsends a message in Signal.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | Yes | Must be true to proceed — prevents accidental deletion |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, but the description goes well beyond them: the confirm guard and its failure mode, the local-only blast radius (nothing removed from Signal, phone, or other devices), the fact that downloaded attachment files on disk survive, and irreversibility except via re-import. That is the extra behavioral context annotations cannot carry.
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?
Four dense sentences, all front-loaded: what it destroys, the guard, the blast radius, the recovery path, the return shape. No filler and no repetition of the name.
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?
For a one-parameter irreversible mutation with no output schema, the description supplies everything needed: destruction scope, safety gate, side-effect boundaries, reversibility, and even the return shape ({deleted: count, status: 'cleared'}). Nothing an agent needs before calling it is missing.
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 coverage is 100% and the single parameter is self-documenting, so the baseline is 3. The description adds genuine meaning beyond the schema's 'Must be true to proceed' by specifying the semantics are exact — confirm must be exactly true, otherwise nothing is deleted and an error is returned.
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?
States a specific verb (delete), resource (ALL messages and attachment records), and scope (signal-mcp's local database), with 'ALL' and 'local' doing real disambiguating work against siblings that also delete things. An agent can distinguish it from delete_local_messages, prune_store, and delete_message without opening any schema.
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 routes the agent: delete_local_messages for a single conversation, prune_store for old messages only, delete_message for unsending in Signal. It also names the recovery path (import_desktop, re-receive). This is exactly the when/when-not/alternatives guidance the dimension asks for.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_groupA
Create a new Signal group with you as admin. name (required) is the group name shown to everyone; members (required) is a list of E.164 phone numbers to add; description (optional) is the group info text; avatar (optional) is a local image path, which must be inside the allowed send folders (SIGNAL_MCP_SEND_ROOTS). Contacts Signal's servers and notifies every member; not idempotent — calling twice creates two groups. Returns status, groupId (base64; use it as group_id elsewhere), timestamp and per-member send results. Use update_group to change an existing group and send_group_message to post in it.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Group name visible to all members | |
| avatar | No | Optional local image file path for the group avatar | |
| members | Yes | Phone numbers (E.164) of initial members to invite | |
| description | No | Optional group description shown in group info |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=false and openWorldHint=true, but the description adds the concrete consequences: it contacts Signal's servers, notifies every member, creates a second group if called twice, and discloses the returned fields. It does not cover permission/admin-setup requirements or rate limits, so it stops short of a 5.
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?
Front-loaded with the core action, then parameters, side effects, returns and alternatives in a compact sequence. It is dense with clauses but each sentence carries distinct information; no filler.
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?
With no output schema, the description compensates by enumerating return fields (status, groupId, timestamp, per-member results). Combined with side effects, path constraints and sibling routing, an agent has everything needed to call it 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 100%, so the baseline is 3, but the description earns more: it specifies members must be E.164 and that avatar must reside inside SIGNAL_MCP_SEND_ROOTS, a path constraint the schema does not state. It also clarifies how the returned groupId is reused as group_id.
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?
States a specific verb and resource ('Create a new Signal group') plus the implicit role ('with you as admin'). It names two sibling tools it is not (update_group, send_group_message), so an agent can distinguish it without opening any schema.
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 routes the agent: 'Use update_group to change an existing group and send_group_message to post in it.' The when-not condition is stated alongside the alternative, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_pollA
Create a poll and send it to a contact or group. Use vote_poll to vote and terminate_poll to close it. question: the poll text; options: answer strings (at least 2, else an error); multi_select=true lets voters pick several answers (default false = single choice). Give recipient (E.164) for a DM or group_id (from list_groups) for a group; neither is an error. Contacts Signal's servers; not idempotent (each call sends a new poll); shares the 20-sends-per-minute rate limit; not saved to the local store. Returns {status: 'poll created', timestamp} — the timestamp (with your number as author) identifies the poll for vote_poll and terminate_poll.
| Name | Required | Description | Default |
|---|---|---|---|
| options | Yes | List of answer options (minimum 2 required) | |
| group_id | No | Group ID for a group poll — provide this OR recipient | |
| question | Yes | The poll question text | |
| recipient | No | Phone number for a DM poll — provide this OR group_id | |
| multi_select | No | Allow voters to select multiple options (default: false = single choice only) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it warns that each call contacts Signal's servers, is not idempotent, shares a 20-sends-per-minute rate limit, and is not saved to the local store. It also discloses the return shape {status, timestamp} and how the timestamp keys vote_poll/terminate_poll.
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?
Dense but front-loaded, leading with the action before branching into usage and parameter rules. Every clause carries information, though the packed single-paragraph form is slightly heavy.
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?
No output schema exists, but the description supplies the return shape and the identity key needed for follow-up calls. Combined with rich parameter and behavioral detail, an agent has everything needed to invoke it 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 coverage is 100%, yet the description adds real meaning: options must have at least 2 or it errors, multi_select=true enables multi-answer (default single), recipient must be E.164, group_id comes from list_groups, and supplying neither is an error. This compensates for constraints the schema cannot express.
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?
States a specific verb+resource ('Create a poll') plus its delivery scope ('send it to a contact or group'). It explicitly names the sibling tools vote_poll and terminate_poll, so an agent can distinguish the lifecycle stages without opening schemas.
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?
Gives explicit routing ('Use vote_poll to vote and terminate_poll to close it') and states the selection rule for recipient (DM) vs group_id (group), including that providing neither is an error. Edge conditions are surfaced rather than left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_group_messageADestructiveIdempotent
Remote-delete (unsend) a message you sent to a group, removing it for all members on Signal 5.0+ clients. Use delete_message for DMs; admin_delete_message to delete another member's message as admin; delete_local_messages for local-only removal. group_id: from list_groups; target_timestamp: ms timestamp of your message (from the send_group_message result or get_conversation). Irreversible; older clients may silently ignore it; repeating it has no further effect. The local store copy is kept. Returns {status: 'deleted'}.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | Yes | Group ID | |
| target_timestamp | Yes | Timestamp of the message to delete |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=true, but the description adds real context beyond them: irreversibility, that older clients may silently ignore the delete, that repeating it has no further effect, and that the local store copy is retained. It also discloses the return shape ({status: 'deleted'}) since no output schema exists.
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?
Front-loaded with the core action, then routing, then parameter sourcing, then caveats and return value. Despite its length, every clause carries distinct information (version dependency, irreversibility, idempotency, local-copy retention) with no filler.
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?
For a destructive mutation tool with no output schema, the description covers everything an agent needs: safety profile (already in annotations, reinforced here), irreversibility, client-compatibility caveat, idempotency, parameter provenance, and the return value. Nothing material is missing.
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 coverage is 100%, so the baseline is 3, but the description adds provenance the schema lacks: group_id comes from list_groups, and target_timestamp is the ms timestamp of the caller's own message from send_group_message or get_conversation. That sourcing guidance exceeds what the terse schema descriptions ('Group ID', 'Timestamp of the message to delete') provide.
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?
States a specific verb and resource ('Remote-delete (unsend) a message you sent to a group') with precise scope ('removing it for all members on Signal 5.0+ clients'). It explicitly distinguishes itself from the three closest siblings (delete_message for DMs, admin_delete_message, delete_local_messages), so an agent can route correctly without opening any schema.
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?
Gives explicit when-to-use-this vs alternatives: 'Use delete_message for DMs; admin_delete_message to delete another member's message as admin; delete_local_messages for local-only removal.' The selection condition for each alternative is named, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_local_messagesADestructiveIdempotent
Delete the locally stored messages of one conversation from signal-mcp's database. recipient (required): the contact's E.164 phone number or the group ID; your own number deletes only your note-to-self messages. Local only: nothing is unsent from Signal or removed from other devices; irreversible locally. Returns {deleted: count, status: 'deleted'} (0 if nothing matched). Use clear_local_store to wipe everything, prune_store to drop messages by age, delete_message to unsend in Signal.
| Name | Required | Description | Default |
|---|---|---|---|
| recipient | Yes | Phone number or group ID whose messages to delete |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true, idempotentHint=true and readOnlyHint=false, but the description adds genuinely new context: nothing is unsent from Signal or removed from other devices, changes are irreversible locally, and the return shape is {deleted, status} with 0 when nothing matched. This goes well beyond the annotation surface.
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?
Purpose is front-loaded in the first sentence, then recipient semantics, then local-only scope, then alternatives. Dense but every clause carries information; the parenthetical return note is slightly cramped but earns its place.
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?
No output schema exists, yet the description supplies the return shape and the zero-match case, plus the destructive scope and alternatives. For a single-parameter destructive tool, nothing an agent needs is missing.
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 coverage is 100%, so baseline is 3, but the description adds real meaning the schema lacks: recipient accepts E.164 phone number or group ID, and using your own number deletes only note-to-self messages. That special-case behavior is not in 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?
States a precise verb+resource+scope: 'Delete the locally stored messages of one conversation from signal-mcp's database.' The 'locally stored' qualifier immediately distinguishes it from Signal-side deletions, and the sibling routing makes the boundary explicit.
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 names three alternatives and the condition that selects each: clear_local_store to wipe everything, prune_store to drop by age, delete_message to unsend in Signal. Nothing is left to inference about when to reach for this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_messageADestructiveIdempotent
Remote-delete (unsend) a message you sent to one contact, removing it for everyone in the chat on Signal 5.0+ clients. Use delete_group_message for groups; delete_local_messages to remove messages only from the local store. Only your own messages can be deleted — you cannot delete what others sent. recipient: E.164 number of the contact; target_timestamp: ms timestamp of your message (from the send_message result or get_conversation). Irreversible; older clients may silently ignore it; repeating it has no further effect. The local store copy is kept. Returns {status: 'deleted'}.
| Name | Required | Description | Default |
|---|---|---|---|
| recipient | Yes | Phone number of the recipient | |
| target_timestamp | Yes | Timestamp of the message to delete |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive=true and idempotent=true, but the description goes well beyond them: irreversible, older clients may silently ignore it, repeating has no further effect, and the local store copy is retained. These are non-obvious behavioral traits an agent needs before invoking.
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?
Front-loaded with the core action, then alternatives, then constraints, then return value. Dense but each clause carries information; the constraint list is slightly packed but nothing is redundant.
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?
With no output schema, the description still reports the return shape ({status: 'deleted'}), covers irreversibility, idempotency, client-version caveats, and where to obtain the timestamp. Nothing needed to call it correctly is missing.
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 coverage is 100%, so the baseline is 3, but the description adds real value: recipient is specified as an E.164 number and target_timestamp as a millisecond timestamp obtainable from the send_message result or get_conversation. That clarifies format and provenance beyond the schema's generic wording.
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?
States a precise verb and resource ('Remote-delete (unsend) a message you sent to one contact') with explicit scope ('one contact'). It names the two sibling tools it is distinct from, so an agent can route correctly without opening any schema.
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?
Gives explicit routing rules: use delete_group_message for groups and delete_local_messages for local-only removal. It also states the precondition that only your own messages can be deleted, which is exactly the when/when-not guidance needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
edit_messageADestructiveIdempotent
Replace the text of a message you already sent (DM or group); recipients see the new text with an '(edited)' label. Use to fix typos or update information; use delete_message / delete_group_message to retract it instead, and send a new message to reach different people. Only the text changes — attachments, quotes and reactions stay. target_timestamp: ms timestamp of the original (from the send_* result or the message id in get_conversation). message: the new full text (no formatting conversion). Give recipient (E.164) for a DM or group_id (from list_groups) for a group; neither is an error. Signal only accepts edits of your own messages. Contacts Signal's servers and overwrites the stored body locally (the old text is not kept); repeating the same edit has no further effect. Returns {status, target_timestamp}.
| Name | Required | Description | Default |
|---|---|---|---|
| message | Yes | New message text to replace the original | |
| group_id | No | Group ID for a group message edit | |
| recipient | No | Phone number for a DM message edit | |
| target_timestamp | Yes | Timestamp of the message to edit (from get_conversation or send_message response) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: recipients see an '(edited)' label, only text changes while attachments/quotes/reactions stay, only your own messages can be edited, the stored body is overwritten locally and the old text is not kept, and repeating the same edit has no further effect. These details are consistent with destructiveHint=true and idempotentHint=true rather than contradicting them.
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?
Front-loads the core action and the '(edited)' consequence, then routes to alternatives before parameter details. It is dense and information-rich, though a couple of clauses (e.g. the returns note) could be tightened.
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?
For a mutation tool with no output schema, it discloses the return shape ({status, target_timestamp}), the server round-trip, and the local-overwrite behavior. Combined with annotations covering the safety profile, nothing an agent needs to call it correctly is missing.
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 coverage is already 100%, so the baseline is 3, but the description adds real meaning: target_timestamp provenance ('from the send_* result or the message id in get_conversation'), the 'no formatting conversion' constraint on message, and the E.164 / list_groups sourcing for recipient and group_id.
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?
States a specific verb and resource with scope: 'Replace the text of a message you already sent (DM or group)'. It immediately distinguishes itself from send_message and delete_message, so an agent can pick it without opening the schema.
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 names the situations to use it ('fix typos or update information') and the alternatives with their selection conditions: delete_message / delete_group_message to retract, and send a new message to reach different people. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_messagesARead-onlyIdempotent
Export messages from signal-mcp's local store as one JSON or CSV string, for archiving or analysis. format: 'json' (default; full message objects with resolved sender_name/group_name, attachments and extras) or 'csv' (flat columns id, timestamp, sender, sender_name, recipient, group_id, group_name, body, quote_id, is_read). recipient (optional): limit to one conversation, an E.164 phone number or a group ID. since (optional, ISO 8601 datetime, e.g. '2026-01-01T00:00:00'): only messages at or after it; an invalid value returns an error. Read-only. Only messages already in the local store are included (run sync_desktop or receive_messages first). Returns {format, data}. Use get_conversation or search_messages to read messages interactively.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | Only include messages at or after this ISO datetime | |
| format | No | Output format (default: json) | |
| recipient | No | Export only this conversation (phone number or group ID) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the burden is lightened, and the description still adds real behavior: store-scoped data only, a prerequisite sync step, error on an invalid 'since', and the return shape {format, data}. It omits anything about volume/performance or limits on large exports, which keeps it short of a 5.
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?
Front-loaded with purpose, then format, optional params, caveats, return shape, and the alternative tool — a logical order with no filler sentences. It is somewhat dense and re-explains parameter meanings already present in the schema, which costs a little economy.
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?
With no output schema, the description compensates by naming the return object and describing the contents of each format, and it covers the prerequisite and error case. Minor gaps remain around export size/limits and whether CSV escaping is handled, but nothing essential for calling it correctly is missing.
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?
Despite 100% schema coverage, the description adds genuine semantics the schema lacks: what 'json' actually contains (full message objects with resolved sender_name/group_name, attachments, extras), the exact CSV column set, the E.164/group-ID constraint on recipient, an ISO 8601 example for since, and the invalid-value error behavior.
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?
States a specific verb+resource+output form: export messages from signal-mcp's local store as a single JSON or CSV string. It immediately signals how it differs from read-oriented siblings by naming get_conversation and search_messages as the interactive alternatives.
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?
Gives clear context (archiving or analysis, bulk single-string output) and an explicit prerequisite: only messages already in the local store are included, so run sync_desktop or receive_messages first. It routes the agent to get_conversation/search_messages for interactive reading, though it never states an explicit 'do not use this for X' exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_contactARead-onlyIdempotent
Find contacts whose number, name, given/family name, nickname or username contains query (case-insensitive substring; required). Use it to resolve a name to an E.164 number before send_message, or to check that a contact exists; use list_contacts instead to list everyone or filter by blocked status. all_recipients (default false) also searches people outside your address book, e.g. group members known only by their profile name. Reads the local contact store only. Returns a list (possibly empty) of contact objects with number, uuid, name, given_name, family_name, about, blocked and display_name.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Case-insensitive fragment of a name, nickname, username or phone number | |
| all_recipients | No | Also include recipients that are not in your address book (e.g. members of your groups), with their profile names |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint=false and destructiveHint=false. The description adds genuinely new context: that it reads the local contact store only, that the result may be empty, and it enumerates the returned fields — behavior not derivable from the annotations. It stops short of discussing pagination or ordering, so not a 5.
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?
Dense but front-loaded: the matching rule and the query semantics come first, then routing, then the return shape. Every sentence carries information, though the run-on construction makes it slightly heavier than it needs to be.
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?
With no output schema, the description compensates by enumerating the returned contact object fields and noting the list may be empty. Combined with the sibling routing and the local-store scope, an agent has everything needed to call and interpret this 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 coverage is 100%, so the baseline is 3, but the description goes further by stating query is required and case-insensitive, and by explaining what all_recipients=false means in practice (group members known only by profile name). That example adds real meaning beyond the schema's phrasing.
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?
States a specific verb (find) and resource (contacts) plus the exact matching fields (number, name, given/family name, nickname, username) and match semantics (case-insensitive substring). It also names the sibling it is not (list_contacts), so an agent can distinguish it without opening either schema.
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 when to use it (resolve a name to an E.164 number before send_message, or verify a contact exists) and when to use the alternative instead (list_contacts for listing everyone or filtering by blocked status). Both the positive and negative routing conditions are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
finish_change_numberA
Step 2 of moving this Signal account to a new phone number: submits the verification code and completes the change. Call start_change_number first; without it there is no code to verify. number (required): the same new E.164 number given to start_change_number; verification_code (required): the 6-digit code received by SMS or voice call; pin (optional): your Registration Lock PIN, needed only if one is set (see set_pin). Primary device only: on a linked signal-cli setup it fails with 'This command doesn't work on linked devices'. On success the real account is moved to the new number; this cannot be undone except by another change-number round. A wrong pin fails with the number of tries remaining. Returns {status: 'number changed', number}.
| Name | Required | Description | Default |
|---|---|---|---|
| pin | No | Registration lock PIN (required if the account has a PIN set) | |
| number | Yes | The new phone number in E.164 format | |
| verification_code | Yes | 6-digit verification code from SMS/voice |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply generic hints (readOnlyHint=false, idempotentHint=false, openWorldHint=true). The description adds concrete behavior beyond them: primary-device-only restriction with the literal failure message, irreversibility ('cannot be undone except by another change-number round'), and error semantics for a wrong PIN ('fails with the number of tries remaining').
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 step-2 framing and prerequisite are front-loaded, and each sentence carries a distinct fact (prereq, params, device restriction, consequence, error behavior, return value). It is dense rather than padded, though the run-on single paragraph could be split for faster scanning.
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?
No output schema exists, yet the description documents the return value ({status: 'number changed', number}), the prerequisite, the side effect, and the failure modes. For a 3-param, irreversible multi-step tool this covers everything an agent needs before calling.
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 coverage is 100%, so the baseline is 3, but the description adds real meaning the schema lacks: 'number' must be the same value passed to start_change_number, and 'pin' is conditional on a Registration Lock being set. It stops short of adding format nuances beyond E.164, which the schema already states.
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?
States a specific verb (submits the verification code) plus the exact scope: it is step 2 of moving this Signal account to a new phone number. It explicitly positions itself relative to the sibling start_change_number ('Call start_change_number first'), so an agent can separate the two-step flow without opening either schema.
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?
Gives an explicit prerequisite ('without it there is no code to verify') and names the alternative path for the optional PIN parameter ('needed only if one is set (see set_pin)'). It also states the when-not condition: primary device only, failing on linked signal-cli setups.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_attachmentAIdempotent
Look up one received attachment and make sure it is saved locally. filename (required): a filename from list_attachments, or a signal-cli attachment id from a message's attachments; path components such as '../' are rejected. If the file is not in ~/Downloads/signal-attachments, it is copied there from signal-cli's own attachment store (only attachments signal-cli already downloaded; otherwise 'Attachment not found'). Returns {filename, path, size (bytes), modified (ISO datetime)}: metadata and the local path, not the file content. Nothing is sent to Signal. Use send_attachment or send_group_attachment to send a file.
| Name | Required | Description | Default |
|---|---|---|---|
| filename | Yes | Attachment filename (from list_attachments) or signal-cli attachment id |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial context beyond the annotations: it explains the local copy into ~/Downloads/signal-attachments, that only attachments signal-cli already downloaded are available, the exact 'Attachment not found' failure, and that nothing is sent to Signal. This reconciles readOnlyHint=false with destructiveHint=false and idempotentHint=true meaningfully.
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?
Dense but front-loaded: the action and the required parameter come first, then resolution behavior, then return shape, then routing to siblings. Slightly long, though nearly every sentence carries distinct operational detail.
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?
With no output schema, the description compensates by enumerating the return object ({filename, path, size, modified}) and clarifying it returns metadata rather than file content. For a single-parameter, non-destructive read/copy tool this is 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?
Schema coverage is 100% so the baseline is 3, but the description adds real semantics: accepted formats (filename or signal-cli attachment id) and the security constraint that path components such as '../' are rejected. That is genuine information not present in 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?
States a specific verb and resource ('Look up one received attachment and make sure it is saved locally'), and distinguishes itself from siblings by naming list_attachments as the source of the identifier and send_attachment/send_group_attachment as the senders. An agent can route correctly without opening any schema.
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?
Gives clear context and an explicit alternative ('Use send_attachment or send_group_attachment to send a file') plus where the filename comes from (list_attachments or a message's attachments). It does not spell out when-not to use it for other attachment operations, so it falls just short of the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_avatarARead-onlyIdempotent
Return a contact's or group's avatar image as base64, from the copy signal-cli has stored. identifier (required): an E.164 phone number for a contact, or a group id from list_groups for a group (anything that is not a full E.164 number is treated as a group id). Returns identifier, base64 (decode to get the JPEG/PNG bytes) and has_avatar; fails with 'Could not find avatar' when none is stored. Use update_profile with avatar_path to set your own photo, update_group with avatar for a group's.
| Name | Required | Description | Default |
|---|---|---|---|
| identifier | Yes | Phone number (E.164) for a contact or group ID for a group |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, it discloses the source (copy signal-cli has stored), the return shape (identifier, base64, has_avatar), decode format, and the exact failure case 'Could not find avatar'. This is rich context that annotations alone would not provide.
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 core action and avoids filler. It is a dense single paragraph, but every sentence contributes useful information; minor structural improvement could make the return and failure details easier to scan.
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?
There is no output schema, so the description carries the burden of explaining return values, and it does so thoroughly with identifier, base64, and has_avatar. It also covers the failure case, identifier types, and related update tools, making it complete for this one-parameter read 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 coverage is 100%, so the baseline is 3, but the description adds useful meaning: identifier is required, E.164 for contacts, group id from list_groups for groups, and anything not full E.164 is treated as a group id. That heuristic parsing rule goes beyond the schema description.
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 states a specific verb and resource: return a contact's or group's avatar image as base64. It distinguishes the contact vs. group identifier rules and names related setters (update_profile, update_group), so an agent can identify the tool without opening the schema.
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?
It gives concrete identifier conditions and points to update_profile/update_group for setting avatars, which helps route the agent. It does not explicitly state when not to use this tool or name a retrieval alternative, so it has clear context but lacks full exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_conversationAIdempotent
Read the message history of one conversation from the local store (no Signal server call). Use list_conversations to find conversations, search_messages to find text across all chats, get_unread for only new messages. recipient: E.164 number for a DM or a group_id (from list_groups). limit: max messages (default 50, clamped 1-500); offset: skip the newest N for paging back (default 0); since: only messages at or after this ISO datetime (e.g. 2024-01-01T00:00:00; invalid values return an error). Side effect: incoming messages returned are marked read in the local store only — no read receipt is sent (use send_read_receipt). Returns {messages (oldest first; id, sender, sender_name, body, timestamp, attachments, quote_id, reactions, is_read …), total, has_more, limit, offset}. Timestamps are milliseconds: a message's id in get_conversation is its timestamp (sent messages: sent__).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max messages to return (default 50, clamped 1-500) | |
| since | No | Only messages after this ISO datetime (e.g. 2024-01-01T00:00:00) | |
| offset | No | Number of newest messages to skip for pagination (default: 0) | |
| recipient | Yes | E.164 phone number for a DM, or group ID (from list_groups) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false and idempotentHint=true, which is the non-obvious part here. The description explains the side effect well (incoming messages marked read in the local store only, no receipt sent) and that no server call is made. However the marking-read behavior IS the reason readOnlyHint is false, so the description mostly elaborates a trait the annotations already signal, keeping this at a solid 3.
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?
Purpose is front-loaded and every sentence carries information (alternatives, params, side effect, return shape). It is dense and reads as a single packed block, but nothing is redundant.
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?
With no output schema, the description supplies the return shape (messages, total, has_more, limit, offset) and even timestamp/id semantics. Combined with full param and side-effect coverage, nothing needed to call it correctly is missing.
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 coverage is 100%, so baseline is 3, but the description adds genuine meaning: recipient accepts E.164 or group_id, offset is described as 'skip the newest N for paging back', and since notes invalid values return an error. These add semantics beyond the schema text.
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?
States a specific verb+resource ('Read the message history of one conversation') with clear scope ('from the local store, no Signal server call'). It explicitly distinguishes itself from list_conversations, search_messages, and get_unread, so an agent can route without opening any schema.
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?
Names three alternative siblings with the exact condition that selects each (find conversations vs. search across chats vs. only unread). It also documents when to use send_read_receipt instead of relying on this tool for read receipts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_own_numberARead-onlyIdempotent
Return this server's own Signal account number as {number} (E.164, e.g. +4915112345678). Local lookup: no network call, no daemon needed, no side effects. Use it to know which messages are your own (sender == number) or to address send_note_to_self; use list_accounts instead to see every account registered in signal-cli on this machine.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, and openWorld=false, so the safety profile is covered. The description still adds beyond that: it characterizes the operation as a purely local lookup with no network call and no daemon dependency, plus the value's format. It loses the top mark only because 'no side effects' restates destructiveHint=false.
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?
Front-loaded with the core answer, then format, then behavioral traits, then routing to siblings. Every clause (E.164 example, local-lookup guarantee, two use cases, one exclusion) earns its place with no filler.
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?
For a no-parameter, no-output-schema tool, the description supplies the missing return contract itself ({number} in E.164), the operational cost model (local, no network), and sibling routing. Nothing an agent needs to invoke it correctly is absent.
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 takes zero parameters, so there is nothing for the description to disambiguate; per the baseline for 0-param tools this lands at 4. The description correctly adds no parameter noise and instead spends its words on the return value.
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?
States a specific verb+resource ('Return this server's own Signal account number') and pins the exact return format with an E.164 example. It explicitly distinguishes itself from the closest sibling, list_accounts, so an agent can tell them apart without opening either schema.
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?
Names two concrete use cases (knowing which messages are your own via sender == number, and addressing send_note_to_self) and an exclusion with the alternative to pick instead (list_accounts). This is the explicit when/when-not/alternative pattern.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_profileARead-onlyIdempotent
Check one phone number against Signal's servers and return what that lookup provides. number (required, E.164). Returns a contact object whose number and uuid (the Signal account id; null if the number is not registered) are filled; the lookup carries no profile data, so name, given_name, family_name and about come back null. For a contact's profile name and about text use find_contact or list_contacts with all_recipients=true; for their photo use get_avatar; to check many numbers at once use get_user_status. To change your own profile use update_profile.
| Name | Required | Description | Default |
|---|---|---|---|
| number | Yes | Phone number in E.164 format |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly, idempotent, openWorld, non-destructive), and the description goes well beyond them: it discloses that the lookup carries no profile data, that name/given_name/family_name/about always return null, and that uuid is null when the number is unregistered. That is exactly the non-obvious behavior an agent needs to avoid misinterpreting the response.
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?
Four short sentences, each earning its place: purpose and return shape first, then a single routing sentence covering four alternatives. Zero filler and the most decision-relevant fact (null profile fields) is front-loaded.
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?
No output schema exists, so the description carries the return contract itself — contact object with number/uuid, null uuid for unregistered numbers, and null profile fields — plus a full routing map to alternatives. Nothing an agent needs to call this correctly is missing.
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 coverage is 100% and the single parameter is already documented as E.164 in the schema; the description merely restates '(required, E.164)'. With the schema doing the work and only one param, baseline 3 is appropriate — no additional format or edge-case semantics are added.
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?
States a specific verb (check) and resource (one phone number against Signal's servers) and immediately clarifies the scope: a lookup, not a profile fetch. It explicitly distinguishes itself from find_contact/list_contacts/get_avatar/get_user_status, so an agent can pick correctly without opening any schema.
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?
Names four concrete alternatives with the exact condition that selects each: find_contact or list_contacts with all_recipients=true for profile name/about, get_avatar for photos, get_user_status for bulk checks, update_profile for editing your own profile. Explicit when-to-use and when-not-to-use routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_stickerARead-onlyIdempotent
Fetch one sticker image from an installed pack as base64. pack_id (required, hex string) and sticker_id (required, integer) come from list_sticker_packs (packId and stickers[].id) or add_sticker_pack. Read-only. Returns {base64}; the image format is the sticker's contentType from list_sticker_packs (usually image/webp). Use send_sticker or send_group_sticker to send it instead of downloading it.
| Name | Required | Description | Default |
|---|---|---|---|
| pack_id | Yes | Sticker pack ID (hex string from list_sticker_packs) | |
| sticker_id | Yes | Sticker ID within the pack |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint/destructiveHint, so the 'Read-only' sentence is partly redundant, but the description earns its keep by disclosing the return payload ({base64}) and that the image format follows the sticker's contentType, usually image/webp. It does not discuss size limits or failure modes for missing sticker IDs.
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?
Three sentences, front-loaded with the core action and result, then provenance, then the alternative tool. The '(required, hex string)' restatement and 'Read-only' repeat what the schema and annotations already carry, a small amount of waste.
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?
No output schema exists, yet the description compensates by naming the exact return shape and format, plus the ID sources. For a two-parameter read tool, an agent has everything needed to invoke it 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 coverage is 100%, so the baseline is 3, but the description adds real provenance detail beyond the schema: pack_id is a hex string from list_sticker_packs' packId field, and sticker_id maps to stickers[].id. That helps an agent construct valid calls rather than guess.
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?
States a specific verb and resource ('Fetch one sticker image from an installed pack') and even names the return encoding (base64). This clearly separates it from the sibling send_sticker / send_group_sticker tools that deliver rather than fetch.
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 routes the agent: 'Use send_sticker or send_group_sticker to send it instead of downloading it,' which is exactly the when-not guidance needed given the adjacent send tools. It also states where both IDs must come from (list_sticker_packs or add_sticker_pack).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_unreadA
Return new unread incoming messages across all conversations — the default way to check for new messages. If the background service (signal-mcp install-service) is running it reads the local store; otherwise it first polls signal-cli (at most once per 30 s) and adds a _warning suggesting the service. Use get_conversation for a chat's full history, list_conversations for an inbox overview. limit: max messages (default 50, clamped 1-500); the newest are kept. Side effect: returned messages are marked read in the local store only (no read receipt — use send_read_receipt; mark_as_unread to undo). Returns {messages (oldest first; id, sender, sender_name, group_id, group_name, body, timestamp, attachments …), has_more}; if has_more is true call again with the same limit to get the next batch.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max messages to return (default: 50) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate the operation is not read-only, not destructive, not idempotent, and open-world. The description goes further by disclosing the local-store read-marking side effect, the absence of a read receipt, the background service behavior, and the at-most-once-per-30s polling fallback. This gives an agent unusually rich operational context.
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 dense but front-loaded, opening with the tool's primary purpose before detailing side effects, alternatives, parameter behavior, and pagination. Every sentence carries operational value, especially given the absence of an output schema.
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?
With no output schema, the description fully compensates by describing the return object shape, key fields, ordering, and has_more pagination. It also covers side effects, alternative tools, and the optional limit's behavior, leaving no critical invocation gap.
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 single limit parameter is well covered by the schema, but the description adds important semantics missing there: the value is clamped to 1-500 and the newest messages are kept when more exist. That directly affects how an agent should invoke the tool and interpret results.
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 states a specific verb and resource: returns new unread incoming messages across all conversations. It immediately distinguishes this tool as the default way to check for new messages, helping an agent separate it from sibling tools such as get_conversation and list_conversations.
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?
It explicitly says when to use this tool (default check for new messages) and names alternatives for related tasks: get_conversation for full chat history and list_conversations for an inbox overview. It also documents the side effect and points to send_read_receipt and mark_as_unread for receipt/undo behavior.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_user_statusARead-onlyIdempotent
Check whether phone numbers and/or usernames are registered on Signal, in one batch query to Signal's servers. recipients: list of E.164 phone numbers; usernames: list of Signal usernames or username links; at least one of the two is required. Returns one entry per input with recipient, number or username, uuid (null if not registered) and isRegistered. Use it before messaging an unknown number; numbers that hide their discoverability can show as unregistered. For a contact's name or details use find_contact or get_profile.
| Name | Required | Description | Default |
|---|---|---|---|
| usernames | No | List of Signal usernames or username links to check | |
| recipients | No | List of phone numbers (E.164) to check |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds value beyond that by disclosing the return shape (one entry per input with recipient, number/username, uuid null when unregistered, isRegistered) and the discoverability caveat — both absent from annotations. It stops short of describing pagination or rate limiting, hence not a 5.
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?
Three dense sentences with zero filler: purpose and batching first, parameter formats and the at-least-one constraint second, return shape and usage caveat third. Every sentence carries distinct information and the purpose is front-loaded.
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?
There is no output schema, so the description carries the burden of explaining return values and does so (uuid null when unregistered, isRegistered). Combined with the required-parameter constraint, the alternatives for contact lookup, and the discoverability caveat, an agent has everything needed to call and interpret this 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 coverage is 100%, so baseline is 3, but the description adds meaning the schema does not encode: it restates the formats (E.164 for recipients, usernames or username links) and states the cross-parameter constraint 'at least one of the two is required', which the schema cannot express since required is empty.
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?
States a specific verb and resource ('Check whether phone numbers and/or usernames are registered on Signal') plus the scope ('in one batch query to Signal's servers'), and explicitly routes away from find_contact/get_profile for other needs. An agent can distinguish it from list_contacts or get_profile without opening any schema.
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?
Gives an explicit trigger ('Use it before messaging an unknown number') and names the alternatives for adjacent needs ('For a contact's name or details use find_contact or get_profile'). It also warns about a false-negative case (numbers that hide discoverability), which is exactly the kind of when-not guidance an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_webhookARead-onlyIdempotent
Return the webhook URL in effect as {url}, or {url: null} if none is configured. No parameters. The SIGNAL_MCP_WEBHOOK environment variable wins over the URL saved with set_webhook. Read-only, local only. Use set_webhook to change or clear it.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint=false and destructiveHint=false, so the safety profile is covered. The description adds genuinely non-obvious behavior: the SIGNAL_MCP_WEBHOOK environment variable takes precedence over the stored URL, which directly affects how the returned value should be interpreted. It does not cover error or failure behavior, so it falls short of fully rich disclosure.
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?
Three short sentences with zero filler, and the return shape is front-loaded before the precedence rule and the sibling pointer. Every sentence carries distinct information.
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?
With no output schema, the description supplies the return format ({url} or {url: null}), the precedence rule governing the value, and the routing to the mutating alternative. Nothing an agent needs to call and interpret this correctly is missing.
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 takes zero parameters, which is the baseline-4 case. The description confirms this explicitly ('No parameters.'), matching the empty schema with no ambiguity.
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?
States a specific verb and resource ('Return the webhook URL in effect') and even specifies the exact return shape ({url} or {url: null}). It names its counterpart sibling, set_webhook, so an agent can distinguish read from write without opening either schema.
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 names the alternative ('Use set_webhook to change or clear it') and the condition that selects it, plus notes there are no parameters. An agent knows exactly when to call this versus the mutating sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
import_desktopAIdempotent
Import the full message history from Signal Desktop on this machine into signal-mcp's local store, so get_conversation, search_messages and export_messages can see older messages. No parameters. Reads Signal Desktop's encrypted database, which needs sqlcipher installed and the database key: on macOS read from the Keychain ('Signal Safe Storage', may prompt for access), on Linux via secret-tool (libsecret / GNOME Keyring). Signal Desktop must be installed and opened at least once. Only writes to the local store; nothing is sent to Signal. Already stored messages are skipped, so re-running is safe but slow. Only one import can run at a time. Returns {imported, skipped, total, max_ts_ms, platform, source}. Use sync_desktop for later updates; it only reads messages newer than the last sync.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the annotations (idempotentHint=true, destructiveHint=false, openWorldHint=false). It discloses what is read (encrypted local DB, key via macOS Keychain or Linux secret-tool, possible access prompt), what is written (local store only, nothing sent to Signal), idempotency semantics ('already stored messages are skipped, re-running is safe but slow'), and a concurrency constraint ('only one import can run at a time').
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?
Front-loaded with purpose and benefit, then prerequisites, then safety/idempotency/return shape. Every sentence carries operational information, but the description is dense and runs long for a zero-param tool; a minor trim would tighten it.
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?
With no output schema, the description supplies the return shape ({imported, skipped, total, max_ts_ms, platform, source}). Combined with prerequisites, safety guarantees, idempotency, and the sync_desktop alternative, an agent has everything needed to call and interpret this 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?
Zero parameters, so the baseline is 4. The description correctly states 'No parameters' and adds no misleading param info, though there is nothing further to clarify beyond confirming the tool takes no input.
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?
States a specific verb+resource+scope: 'Import the full message history from Signal Desktop on this machine into signal-mcp's local store.' It also names the concrete benefit (older messages visible to get_conversation, search_messages, export_messages) and explicitly contrasts with the sibling sync_desktop, so an agent can pick the right tool without opening a schema.
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?
Gives explicit routing: 'Use sync_desktop for later updates; it only reads messages newer than the last sync.' Prerequisites are spelled out (Signal Desktop installed and opened at least once, sqlcipher installed, database key available), which tells the agent exactly when this call will and won't work.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
join_groupAIdempotent
Join a Signal group from an invite link. uri (required) is the link, https://signal.group/#... Use this for groups you are not in; for groups you already belong to use list_groups. Contacts Signal's servers and notifies the group. If the group requires admin approval you become a requesting member and the result has onlyRequested=true (or the call fails with 'Pending admin approval'); an invalid or reset link fails with 'Group link is invalid'. Returns status, groupId, timestamp and send results; use the groupId as group_id for send_group_message.
| Name | Required | Description | Default |
|---|---|---|---|
| uri | Yes | Group invite link starting with https://signal.group/# |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, openWorldHint=true, idempotentHint=true, destructiveHint=false) by disclosing the network side effect (contacts Signal's servers, notifies the group), the admin-approval path (requesting member, onlyRequested=true, or the 'Pending admin approval' failure), the invalid/reset-link failure text, and the return fields. This is exactly the behavioral context annotations cannot carry.
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?
Front-loads the action and required parameter, then layers usage routing, side effects, failure modes, and return handling. Every sentence carries distinct information and no sentence is filler, despite the overall length.
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?
With no output schema, the description compensates by naming the returned fields (status, groupId, timestamp, send results) and the actionable failure strings. Combined with the routing guidance and side-effect disclosure, nothing an agent needs to call this correctly is missing.
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?
Only one parameter and schema coverage is 100%; the schema already documents uri as 'Group invite link starting with https://signal.group/#'. The description restates the same format with an example, adding little meaning beyond the schema, so the baseline 3 applies.
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?
States a specific verb+resource ('Join a Signal group from an invite link') and immediately distinguishes the case it serves from the alternative ('groups you are not in' vs list_groups). An agent can route between join_group, create_group, and list_groups without opening a schema.
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 when to use it ('groups you are not in') and names the alternative for the other case (list_groups). It also tells the agent where to go next after success, using the returned groupId as group_id for send_group_message.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
leave_groupADestructiveIdempotent
Leave a Signal group yourself: sends a quit message to all members and removes you from the member list; the group continues for everyone else. To end the group for all members use terminate_group instead. group_id (required, from list_groups). admins: E.164 numbers of members to promote first — if you are the group's ONLY admin you must name one, otherwise signal-cli refuses. delete (default false): also delete the group's local data after leaving. You can only come back by being re-added or via an invite link. Returns status and group_id.
| Name | Required | Description | Default |
|---|---|---|---|
| admins | No | Members to make admin before leaving — required if you are the only admin | |
| delete | No | Also delete all local group data after leaving | |
| group_id | Yes | Group ID to leave (get from list_groups) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint and idempotentHint, but the description adds far more: a quit message is sent to all members, you are removed from the member list, the group survives for others, naming an admin is mandatory when you are the sole admin, and the irreversible re-entry constraint (re-added or invite link). This is rich context well beyond the structured fields.
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?
Purpose and the sibling alternative are front-loaded in the first sentence, followed by parameters and the return value. Dense but every clause carries information; only marginal tightening is possible.
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?
No output schema exists, yet the description states the return value ('status and group_id'), covers all three parameters including defaults, and discloses the admin-promotion prerequisite and re-entry consequences. Complete for an agent to 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 coverage is 100%, so baseline would be 3, but the description goes further by giving the 'delete' default (false) and the consequence of setting it, which the schema does not state, and reinforces the group_id provenance. It slightly exceeds what the schema already provides.
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?
States a specific verb and resource ('Leave a Signal group yourself') and precisely distinguishes the scope from its closest sibling by naming terminate_group as the tool for ending the group for everyone. An agent can select between them without opening either schema.
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 names the alternative (terminate_group) and the condition that selects it, plus a hard prerequisite ('if you are the group's ONLY admin you must name one, otherwise signal-cli refuses'). When-to-use, when-not-to-use, and the failure mode are all covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_accountsARead-onlyIdempotent
List every Signal account registered in signal-cli on this machine. Returns a JSON array of E.164 phone numbers (e.g. ["+4915112345678"]); no registration status or other fields. Read-only, asks the running signal-cli daemon. Most setups have exactly one account. Use get_own_number instead to get the single account this server sends and receives as.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already carry the safety profile (readOnlyHint, idempotentHint, destructiveHint=false, openWorldHint=false), and the description goes well beyond them by disclosing the exact return shape (JSON array of E.164 numbers only, no registration status), the fact that it queries the running signal-cli daemon, and the common case of a single account. That is substantive behavioral context an agent needs.
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?
Three short sentences, front-loaded with what it returns, then constraints, then the sibling routing. Nothing redundant; every clause carries information.
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?
No output schema exists, so the description properly compensates by specifying the return type and its exact contents, plus the daemon dependency and typical cardinality. Nothing an agent needs to invoke it correctly is missing.
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?
There are zero parameters and schema coverage is 100%, so the baseline of 4 applies; the description correctly makes no attempt to invent parameters and confirms the call takes no arguments.
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?
States a specific verb (List) and resource (Signal accounts registered in signal-cli on this machine), and explicitly distinguishes itself from get_own_number, the closest sibling. An agent can tell exactly which of the 70+ siblings this is without opening a schema.
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?
Names the alternative tool (get_own_number) and the condition that selects it: this tool enumerates all registered accounts, while get_own_number returns the single sending/receiving identity. That is explicit when-to-use/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_attachmentsARead-onlyIdempotent
List the attachment files saved in the local attachments folder (~/Downloads/signal-attachments). No parameters. Returns an array of {filename, path, size (bytes), modified (ISO datetime)}, sorted by filename; empty if the folder does not exist. Read-only and local; nothing is downloaded. Pass a filename to get_attachment for its details. Attachments of incoming messages land here when messages are received (receive_messages or the background service).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint=false, and the description reinforces this with 'Read-only and local; nothing is downloaded.' It goes further by disclosing the empty-folder behavior and where attachments originate, which annotations cannot express.
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?
Front-loaded with the core action and scope, then return shape, then routing. Dense with semicolon-separated facts, but every clause carries information an agent needs; slightly long but not padded.
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?
With no output schema, the description supplies the return structure ({filename, path, size, modified}, sorted by filename, empty when the folder is missing), which is exactly what is needed. Nothing required to call it correctly is missing.
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?
Zero parameters, so the baseline is 4. The description still explicitly states 'No parameters,' removing any doubt about whether a path or filter argument 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?
States a specific verb and resource (list attachment files) plus the exact scope (the local ~/Downloads/signal-attachments folder). It is clearly distinguishable from siblings get_attachment (details for one file) and send_attachment (uploading), which it references by name.
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?
Routes the agent explicitly: 'Pass a filename to get_attachment for its details,' and clarifies the relationship to receive_messages and the background service that populates the folder. It lacks an explicit when-not-to-use statement, but the context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_contactsARead-onlyIdempotent
List the contacts in signal-cli's local contact store (no network call). Use it to browse or audit contacts; to look up one person's number by name, find_contact is the shorter call. Parameters: search (optional) keeps only contacts whose number, name, given/family name, nickname or username contains it (case-insensitive); all_recipients (default false) also includes people not in your address book, e.g. members of your groups; blocked=true returns only blocked contacts, false only unblocked, omitted all. Returns a list of objects with number (E.164), uuid, name, given_name, family_name, about, blocked, display_name, plus username, nick_name, note, has_avatar, message_expiration_time etc. when set.
| Name | Required | Description | Default |
|---|---|---|---|
| search | No | Filter contacts by name or number (case-insensitive substring match) | |
| blocked | No | true = only blocked contacts, false = only unblocked (omit for all) | |
| all_recipients | No | Also include recipients that are not in your address book (e.g. members of your groups), with their profile names |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so safety is covered. The description adds genuinely new context: it operates on the local store with 'no network call', which sharpens the openWorld hint into an actionable fact. It does not discuss result size or ordering, which is a minor gap.
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?
Front-loaded with the core purpose and the sibling routing, then parameters, then return shape. Dense and mostly waste-free, though the return-field enumeration runs long as one comma-separated tail.
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?
No output schema exists, and the description compensates by naming the returned fields (number, uuid, name, given_name, blocked, etc.). With 100% parameter coverage plus return shape plus sibling routing, an agent has everything needed to call this 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 coverage is 100%, so baseline is 3, but the description goes beyond the schema: the schema says search matches 'name or number' while the description enumerates number, name, given/family name, nickname and username. It also spells out the tri-state blocked semantics and gives a concrete example for all_recipients.
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?
States a specific verb and resource (list contacts in signal-cli's local contact store) and immediately distinguishes itself from the sibling find_contact, which does the narrower single-person lookup. An agent can select between the two without opening either schema.
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?
Explicit when-to-use ('browse or audit contacts') and names the alternative with the condition that selects it ('to look up one person's number by name, find_contact is the shorter call'). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_conversationsARead-onlyIdempotent
List every conversation (direct and group) in the local store, most recent first — an inbox overview. Takes no parameters. Use get_conversation to read one, get_unread for only new messages, search_messages to find text. Reads only locally stored messages (no Signal server call; nothing marked read); names come from the cached signal-cli contacts and groups. Returns a list of {id (E.164 number or group_id — pass to get_conversation), type ('direct' | 'group'), name, last_message, last_message_at (ISO), message_count, unread_count}.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, non-openWorld), and the description adds substantial context beyond them: it reads only locally stored messages, makes no Signal server call, marks nothing as read, and names come from the cached signal-cli contacts/groups. This is exactly the extra behavioral disclosure that structured fields cannot convey.
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?
Front-loaded with purpose and scope, then alternatives, then behavioral caveats, then the return shape. Despite being dense, every sentence carries actionable information with no filler.
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?
No output schema exists, so the description compensates by enumerating the full return shape (id, type, name, last_message, last_message_at, message_count, unread_count) and even explains how to pass the id onward. Nothing an agent needs to call and consume this tool correctly is missing.
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 zero parameters the baseline is 4; the description confirms 'Takes no parameters,' which is consistent with the empty schema. There is no further parameter meaning to add.
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?
States a specific verb (List) and resource (every conversation, direct and group) with scope ('in the local store, most recent first — an inbox overview'). It clearly differentiates itself from sibling readers like get_conversation, get_unread, and search_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 routes the agent to alternatives with conditions: 'Use get_conversation to read one, get_unread for only new messages, search_messages to find text.' Nothing is left to inference about when to pick this tool versus its neighbors.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_devicesARead-onlyIdempotent
List all devices linked to your Signal account, queried from Signal's servers. Takes no parameters. Returns entries with id, name, createdTimestamp and lastSeenTimestamp (epoch ms); device id 1 is the primary phone. Use it to audit which devices have access, or to get the device id for update_device (rename) or remove_device (unlink).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds genuine context beyond them: the query is a server round-trip (not a local cache read) and it spells out the returned fields, which matters because no output schema exists.
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?
Three tight sentences: what it does, the shape of the result, then when to use it. The routing hint to update_device/remove_device is front-loaded at the end where it is most actionable, and no sentence is filler.
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?
For a parameterless read tool with no output schema, the description supplies exactly what is missing: the origin of the data, the returned field names, and the semantics of the notable value (device id 1 is the primary phone). An agent can call this and interpret the response without further documentation.
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?
Zero parameters, so per the rubric this is a baseline 4. The description explicitly confirms 'Takes no parameters,' which is consistent with the empty schema and removes any doubt for the agent.
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?
States a specific verb and resource ('List all devices linked to your Signal account') and adds the provenance detail that results come from Signal's servers rather than a local store. That scoping distinguishes it clearly from siblings like add_device, update_device, and remove_device.
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 names two use cases (audit device access, obtain a device id) and routes to the tools that consume that id: update_device for rename and remove_device for unlink. Nothing is left to inference about when to reach for this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_groupsARead-onlyIdempotent
List the Signal groups this account knows, from signal-cli's local store (no network call). Call it first to get the group_id that send_group_message, send_group_attachment, update_group, leave_group, terminate_group and set_expiration_timer require, or to check your admin status. group_id (optional) returns only that group. Each group has id, name, description, member_count, members (uuid, number, is_admin, and label/label_emoji — the tag shown next to the name — when set), is_blocked, is_member and invite_link; when non-empty also pending_members (invited), requesting_members (awaiting approval), banned, permission_add_member/permission_edit_details/permission_send_message (EVERY_MEMBER or ONLY_ADMINS), message_expiration_time (seconds) and is_terminated.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | No | Optional: return only this group |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly, idempotent and no-network semantics, but the description reinforces the no-network behavior and, importantly, enumerates the full return shape since no output schema exists. It doesn't mention pagination or large-store performance, which keeps it short of a 5.
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?
Front-loaded with purpose and usage before the return-field enumeration, and every clause is dense and useful. The long field list is justified by the absence of an output schema, though it is still fairly heavy.
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?
For a list tool with no output schema, the description fully documents the return fields (including pending/requesting/banned members and permission enums) and the local-store behavior. An agent has everything needed to call and interpret it.
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 coverage is 100%, so the schema already documents group_id. The description restates that group_id returns only that group but adds no syntax or format detail beyond the schema; baseline 3 is appropriate.
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?
States a specific verb and resource ('List the Signal groups this account knows') plus scope ('from signal-cli's local store'). Clearly distinguishes itself from mutation siblings like update_group and leave_group.
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 to call it first to obtain the group_id that send_group_message, update_group, leave_group, terminate_group and set_expiration_timer require, and to check admin status. This names both the purpose and the downstream dependents, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_identitiesARead-onlyIdempotent
List stored Signal identity keys (safety numbers) and their trust levels, from the local store. number (optional, E.164) limits the result to one contact; omit it for all. Returns entries with number, uuid, fingerprint, safetyNumber, scannableSafetyNumber, trustLevel and addedTimestamp (epoch ms). trustLevel is TRUSTED_VERIFIED (manually verified), TRUSTED_UNVERIFIED (trusted on first use) or UNTRUSTED (key changed; sending is blocked until re-trusted). Use it when Signal reports 'safety number changed' or before trust_identity; it does not change trust itself.
| Name | Required | Description | Default |
|---|---|---|---|
| number | No | Only this contact's keys (E.164 phone number); omit for all |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only/idempotent safety profile, so the bar is lower, yet the description adds substantial context: trustLevel states TRUSTED_VERIFIED, TRUSTED_UNVERIFIED and UNTRUSTED, and notes that UNTRUSTED blocks sending until re-trusted, plus that the tool never mutates trust. That is meaningful behavioral disclosure beyond the annotations.
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?
Front-loads the purpose, then the filter, then the return shape, then the trust semantics and usage trigger. Sentences are dense but every one carries information an agent needs, with no filler.
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?
With no output schema, the description compensates by enumerating all returned fields (number, uuid, fingerprint, safetyNumber, scannableSafetyNumber, trustLevel, addedTimestamp) and explaining the enum-like trust levels. Nothing needed to call or interpret it is missing.
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 100% and the single parameter is fully documented there, so baseline 3 applies. The description restates E.164 format and the omit-for-all behavior without adding syntax or format detail 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?
States a specific verb and resource ('List stored Signal identity keys (safety numbers) and their trust levels, from the local store'), immediately distinguishing it from siblings like trust_identity and list_contacts. An agent knows exactly what data comes back without opening a schema.
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?
Gives explicit triggers ('Use it when Signal reports safety number changed or before trust_identity') and an explicit exclusion of what it does not do ('it does not change trust itself'), which routes the agent to trust_identity for mutations. The 'omit it for all' filtering condition is also spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_scheduled_messagesARead-onlyIdempotent
List messages scheduled with schedule_message, ordered by send time. include_done (boolean, default false): also include jobs that were sent, cancelled or failed; by default only pending jobs are listed. Read-only, local only. Returns an array of {id, recipient, group_id, message, send_at, created_at, status ('pending'|'sent'|'cancelled'|'failed'), error}. Use the id with cancel_scheduled_message; run_scheduled_messages sends the pending jobs that are due.
| Name | Required | Description | Default |
|---|---|---|---|
| include_done | No | Include already-sent, cancelled, and failed messages (default: false) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, destructive=false, openWorld=false), so the bar is lower. The description still adds value beyond them: 'local only' scope, the full return array shape with the status enum values, and the presence of an `error` field.
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?
Four dense sentences, front-loaded with the verb and resource, then filter semantics, then return shape, then cross-tool routing. No filler and nothing redundant with the schema.
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?
No output schema exists, yet the description supplies the return record fields and status values, plus the single parameter's semantics and relationships to the two sibling scheduling tools. An agent has everything needed to call and interpret it.
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 coverage is 100%, so baseline is 3, but the description earns above baseline by spelling out what 'done' actually means — sent, cancelled, or failed — and restating the default. That clarifies the filter semantics more than the terse schema field does.
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?
Specific verb+resource: 'List messages scheduled with schedule_message, ordered by send time.' It names the producing tool and the ordering, and clearly distinguishes itself from siblings schedule_message, cancel_scheduled_message, and run_scheduled_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 scopes default behavior (pending only) vs. include_done, and routes the agent by naming the id's downstream use (cancel_scheduled_message) and the complementary sender (run_scheduled_messages). No 'when-not-to-use' clause, but the effective context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_sticker_packsARead-onlyIdempotent
List the sticker packs installed on this Signal account. No parameters. Returns signal-cli's array of packs: {packId (hex), url, installed, title, author, cover, stickers: [{id, emoji, contentType}]}. Read-only. Use packId and a sticker id with send_sticker, send_group_sticker or get_sticker. Use add_sticker_pack to install a pack from a signal.art link.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered; the description reinforces "Read-only" (mildly redundant) but adds genuine value by spelling out the returned pack structure, which no annotation conveys. It doesn't mention pagination or error behavior, but for a parameterless local list that gap is minor.
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?
Front-loaded with the purpose, then compactly covers the empty signature, the return shape, the safety profile, and the downstream siblings. Every sentence carries distinct information with no padding.
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?
With no output schema and no parameters, the description compensates by documenting the exact array shape returned, including pack fields and nested sticker fields. An agent has everything needed to call it and consume the result.
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 takes zero parameters, so per the rubric the baseline is 4. The description explicitly confirms "No parameters," leaving nothing ambiguous.
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?
States a specific verb and resource with scope ("List the sticker packs installed on this Signal account"). It is immediately distinguishable from siblings like add_sticker_pack, get_sticker, and upload_sticker_pack without opening any schema.
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?
It routes the agent to the relevant siblings: use packId/sticker id with send_sticker, send_group_sticker or get_sticker, and use add_sticker_pack to install. It gives clear context for the tool's role in the sticker workflow, though it never states an explicit condition for choosing this listing tool over any other alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mark_as_unreadAIdempotent
Mark messages as unread again in the local signal-mcp store, so get_unread returns them on its next call — e.g. to flag for follow-up. Local only: read receipts already sent and other devices are unaffected (send_read_receipt is the opposite, outward action). message_ids: list of message id strings exactly as returned by get_conversation, get_unread or search_messages; unknown ids are ignored. Idempotent. Returns {status, count} where count is the number of ids passed.
| Name | Required | Description | Default |
|---|---|---|---|
| message_ids | Yes | Message id strings as returned by get_conversation, get_unread or search_messages |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly=false, destructive=false, idempotent=true, openWorld=false, but the description adds what those flags cannot: that the change is local-only, that already-sent read receipts and other devices are unaffected, that unknown ids are silently ignored, and the exact return shape {status, count}. The 'unknown ids are ignored' behavior is especially valuable side-effect disclosure.
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?
Front-loads the action and the store scope, then layers consequence, scope caveat, parameter semantics and return shape in short clauses. Every sentence carries distinct information; nothing repeats the schema or annotations without adding meaning.
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?
There is no output schema, yet the description supplies the return contract ({status, count} where count is the number of ids passed), the idempotency guarantee, and the blast radius of the mutation. For a single-parameter local mutation tool, an agent has everything needed to call it 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 coverage is 100% so the baseline is 3, but the description earns an extra point by telling the agent where valid ids come from ('exactly as returned by get_conversation, get_unread or search_messages') and what happens to ids that don't resolve. It doesn't add ordering or size-limit constraints, so it isn't a full 5.
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?
Names a specific verb (mark as unread) plus resource (messages) and scopes it precisely to the local signal-mcp store, then states the observable consequence ('so get_unread returns them on its next call'). It also distinguishes itself from the sibling it most resembles, send_read_receipt, calling it 'the opposite, outward action'.
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?
Gives a concrete motivating scenario ('e.g. to flag for follow-up') and points at the contrasting sibling (send_read_receipt) for the outward case. It stops short of explicit when-not conditions or edge-case routing, but the context is clear enough to choose between the two.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pin_messageAIdempotent
Pin a message at the top of a DM or group conversation for all participants. Pinning is visible to everyone — don't use it as a private bookmark (send_note_to_self instead). Use unpin_message to remove a pin. target_author: E.164 number of the message's sender; target_timestamp: its ms timestamp (message id in get_conversation). Give recipient (E.164) for a DM or group_id for a group; neither is an error. Contacts Signal's servers; pinning an already pinned message changes nothing. Returns {status: 'message pinned'}.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | No | Group ID for group conversations — provide this OR recipient | |
| recipient | No | Phone number for DM conversations — provide this OR group_id | |
| target_author | Yes | Phone number of the message author (E.164) | |
| target_timestamp | Yes | Timestamp of the message to pin (from get_conversation) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare openWorldHint, idempotentHint, and non-destructive, so the bar is lower. The description still adds real context beyond them: the pin is publicly visible to all participants, the call contacts Signal's servers, and re-pinning is a no-op (restating idempotency in plain terms). Only the return shape and any auth/rate-limit caveats are left implicit.
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?
Front-loaded with the core action and visibility caveat before the routing advice and parameter notes; every sentence carries information. It is dense as a single block, and the parameter guidance is interleaved with usage guidance rather than separated, which slightly hurts scannability.
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?
For a 4-parameter mutation with no output schema, the description covers the missing return contract ('Returns {status: \'message pinned\'}'), the visibility consequence, the idempotent behavior, and both conversation-targeting modes. An agent has everything needed to call it 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 coverage is 100%, so baseline is 3, but the description adds format meaning the schema lacks: E.164 for target_author, millisecond timestamp, and the provenance of the value ('message id in get_conversation'). It also restates the recipient/group_id mutual-exclusivity in prose. It does not, however, clarify failure modes for ambiguous or mismatched identifiers.
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?
States a specific verb (pin) and resource (message) with explicit scope: at the top of a DM or group conversation, visible to all participants. It actively distinguishes itself from two siblings by name (send_note_to_self for private bookmarks, unpin_message for removal), so an agent can route correctly without opening any schema.
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?
Explicit when-not guidance ('don't use it as a private bookmark — send_note_to_self instead') plus the inverse operation (unpin_message) and the recipient-vs-group_id selection rule including the 'neither is an error' edge case. Nothing about tool selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
prune_storeADestructiveIdempotent
Delete locally stored messages older than a number of days from signal-mcp's database, together with their attachment records and search index entries. days (integer, default 180, must be positive): messages with a timestamp older than now minus this many days are deleted. Local only: nothing is deleted from Signal; irreversible locally. Returns {deleted: count, older_than_days}. Use it to keep the store small; use delete_local_messages for one conversation or clear_local_store to wipe everything.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Delete messages older than this many days (default: 180) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, idempotentHint=true and openWorldHint=false, but the description adds material context beyond them: the operation is local-only, nothing is removed from Signal itself, it is irreversible locally, and it cascades into attachment records and search index entries. It also discloses the return shape {deleted, older_than_days}, which the absence of an output schema makes valuable.
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 text is a single dense paragraph that front-loads the core action before moving to parameter semantics, return value, and sibling routing. It is slightly long and the parameter sentence partially restates the schema default, but no sentence is wasted.
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?
For a one-parameter destructive tool with no output schema, the description covers the action, its cascade effects, irreversibility, local-only scope, parameter semantics, return shape, and alternatives. An agent has everything needed to call it correctly or choose a sibling instead.
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 coverage is 100% so the baseline is 3, but the description adds the positivity constraint ("must be positive") and the precise comparison semantics (timestamp older than now minus N days) that the schema's one-line description does not spell out. That is a modest but real increment over the structured field.
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 states a precise verb (delete) plus resource (locally stored messages older than N days) and explicitly scopes it to signal-mcp's database, including the cascading deletion of attachment records and search index entries. It also names the siblings it is not (delete_local_messages, clear_local_store), so an agent can distinguish it immediately.
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?
It gives an explicit when-to-use ("keep the store small") and routes the agent to two named alternatives with their distinguishing conditions: delete_local_messages for one conversation, clear_local_store to wipe everything. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
react_to_messageAIdempotent
Add or remove your emoji reaction on a message in a DM or group. Use to acknowledge without replying; use send_message / send_group_message for a text reply. target_author: E.164 number of the message's sender; target_timestamp: its ms timestamp (message id in get_conversation, or a send_* result). emoji: e.g. '👍'. Give recipient (E.164) for a DM or group_id for a group; neither is an error. You have at most one reaction per message: a new emoji replaces the old one, repeating the same one changes nothing. remove=true retracts that reaction (emoji still required; default false). Contacts Signal's servers; not stored locally. Returns {status: 'reaction sent' | 'reaction removed'}.
| Name | Required | Description | Default |
|---|---|---|---|
| emoji | Yes | Emoji to react with (e.g. '👍') | |
| remove | No | Remove an existing reaction (default false) | |
| group_id | No | Group ID for group reactions | |
| recipient | No | Phone number for DM reactions | |
| target_author | Yes | Phone number of the message author | |
| target_timestamp | Yes | Timestamp of the message to react to |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, idempotentHint=true, openWorldHint=true), and the description still adds substantive behavior: the one-reaction-per-message rule, replace-vs-no-op semantics for repeated emoji, remove=true retraction with emoji still required, and that the change hits Signal's servers rather than local storage. It even names the return payload, which no output schema provides.
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?
Front-loads the action and its purpose in the first clause, then layers targeting, semantics, and return value in a tight sequence. It is dense and semicolon-heavy, but every sentence carries distinct information rather than repetition.
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?
For a six-parameter mutation with no output schema, the description covers sourcing the target identifiers, the mutual-exclusivity of recipient/group_id, replacement and retraction semantics, and the return shape. Nothing an agent needs to call this correctly is missing.
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 coverage is 100%, so the baseline is 3, but the description goes further: it specifies target_author as the sender's E.164, explains that target_timestamp is a millisecond value obtainable from get_conversation or a send_* result, and clarifies the recipient/group_id pairing and the default of remove. Only minor gaps remain (no note on timestamp unit edge cases).
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?
States a precise verb+resource ('Add or remove your emoji reaction on a message') and scopes it to DMs or groups. It explicitly contrasts itself with the sibling text-reply tools (send_message / send_group_message), so an agent can route correctly without opening a schema.
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?
Gives an explicit when-to-use ('to acknowledge without replying') and names the alternatives for the other case. It also states the routing rule between the two targeting modes ('Give recipient for a DM or group_id for a group; neither is an error'), leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
receive_directA
Troubleshooting fallback: receive messages by running signal-cli receive directly, bypassing the daemon. Use only when receive_messages / get_unread fail because the daemon is stuck; it stops the daemon (holding a lock file meanwhile), runs the receive, and the daemon restarts on the next call. timeout: seconds to wait (default 5); max_messages: stop after this many (default: no limit); ignore_attachments, ignore_stories, ignore_avatars, ignore_stickers (all default false) skip downloading those. Received messages are saved to the local store and remote deletes applied; nothing is marked read. Returns a list of messages in the same shape as receive_messages; errors if signal-cli exits non-zero.
| Name | Required | Description | Default |
|---|---|---|---|
| timeout | No | Seconds to wait for messages (default: 5) | |
| max_messages | No | Return after this many messages (default: no limit) | |
| ignore_avatars | No | Don't download avatars | |
| ignore_stories | No | Don't receive story messages | |
| ignore_stickers | No | Don't download sticker packs | |
| ignore_attachments | No | Don't download attachments |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: it stops the daemon and holds a lock file, the daemon restarts on the next call, received messages are saved locally, remote deletes are applied, nothing is marked read, and it errors on non-zero exit. These are exactly the side effects an agent needs to know before invoking a non-read-only 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?
Front-loads the fallback framing and the daemon/lock caveat before parameters, and each clause carries information. Slightly dense, but no sentence is wasted.
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?
With no output schema, the description covers the return shape ('same shape as receive_messages'), error behavior, and local-store side effects. An agent has everything needed to call it 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 coverage is 100%, so the schema already documents all six parameters with defaults. The description restates timeout, max_messages and the ignore_* flags, adding only marginal framing ('skip downloading those'), so baseline 3 applies.
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?
States a specific verb+resource ('receive messages by running signal-cli receive directly, bypassing the daemon') and immediately frames it as a troubleshooting fallback, which distinguishes it from the receive_messages / get_unread siblings.
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 names when to use it ('only when receive_messages / get_unread fail because the daemon is stuck') and the alternatives it replaces, plus the condition that resolves the choice. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
receive_messagesA
Poll the signal-cli daemon once for newly arrived messages and save them to the local store. Normally use get_unread instead — it polls when needed and returns unread messages in one call; use receive_direct only if the daemon is stuck. timeout: seconds to wait (integer, default 5); max_messages: stop after this many (default: no limit). Incoming edits and remote deletes are applied to stored messages instead of being returned; receipts are returned but not stored. Does not mark anything read. Returns a list of messages (id, sender, sender_name, recipient, group_id, group_name, body, timestamp, attachments, quote_id, reactions, is_read). If the background service already holds the receive lock, returns {note, messages} with up to 50 unread messages from the store instead.
| Name | Required | Description | Default |
|---|---|---|---|
| timeout | No | Seconds to wait for messages (default: 5) | |
| max_messages | No | Return after this many messages (default: no limit) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide only generic hints (readOnlyHint=false, openWorldHint=true, idempotentHint=false, destructiveHint=false). The description adds substantial non-obvious behavior: edits and remote deletes are applied to stored messages rather than returned, receipts are returned but not stored, nothing is marked read, and a fallback shape {note, messages} is returned if the receive lock is held. This is exactly the kind of context annotations cannot convey.
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?
Dense and front-loaded: behavior, routing, parameters, side effects, and return shape in a compact block. Every sentence carries signal, though the return-field enumeration is a long list that slightly taxes readability.
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?
For a non-idempotent, open-world polling tool with no output schema, the description covers side effects (what is stored vs returned, edits/deletes applied, nothing marked read), the return shape, and the lock-contention fallback. Nothing an agent needs to call it correctly is missing.
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 100%, so the schema already documents timeout and max_messages. The description restates the defaults but adds no syntax or constraint details beyond the schema. Baseline 3 for full schema coverage.
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?
States a specific verb and resource ('Poll the signal-cli daemon once for newly arrived messages and save them to the local store') and explicitly differentiates from siblings get_unread and receive_direct, with a clear default preferred path.
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 when to use this vs alternatives: 'Normally use get_unread instead', and 'use receive_direct only if the daemon is stuck'. This is textbook when/when-not/alternatives guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_contactADestructiveIdempotent
Delete a contact's entry (name, nickname, note) from your contact list; synced to your linked devices. It does not block them, delete messages or stop them messaging you — use block_contact for that. number (required, E.164). hide (default false): only hide the contact from the list and keep its data. forget (default false): delete ALL data for this recipient, including identity keys and sessions — not reversible. hide and forget are mutually exclusive (error if both). Returns status 'removed' and number. To rename instead, use update_contact.
| Name | Required | Description | Default |
|---|---|---|---|
| hide | No | Hide the contact but keep its data | |
| forget | No | Delete all data for this recipient, including identity keys and sessions | |
| number | Yes | Phone number to remove (E.164 format) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, but the description goes further: it discloses that changes sync to linked devices, that forget is irreversible and wipes identity keys and sessions, that hide/forget are mutually exclusive with an error on conflict, and that the result status is 'removed'. That is substantial behavior beyond the annotations.
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?
Dense but front-loaded: the core action and its scope boundaries come first, then parameter caveats and the result shape. Every sentence adds an actionable fact (alternatives, irreversibility, exclusivity, return value) without filler.
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 no output schema, the description states what is returned ('status removed' and number), covers the destructiveness and irreversibility of forget, and routes to sibling tools. Nothing an agent needs to call this safely is missing.
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 coverage is 100%, so the baseline is 3, but the description adds real meaning: it clarifies that hide keeps data versus forget deleting ALL data, and it documents the mutual-exclusivity constraint and error behavior that the schema does not express. It stops short of five only because the core per-parameter semantics largely duplicate 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?
States a specific verb (Delete) and resource (a contact's entry) and immediately delimits scope by saying it does not block, delete messages, or stop messaging. This clearly distinguishes it from siblings block_contact and update_contact without opening their schemas.
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 names when-not to use it ('use block_contact for that') and names the alternative for a related operation ('To rename instead, use update_contact'). Both exclusion and redirect are stated rather than implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_deviceADestructiveIdempotent
Permanently unlink a device from your Signal account; it immediately stops sending and receiving and can only come back by linking again with add_device. device_id (required, integer from list_devices) must be a linked device, not 1 (the primary). Only works when signal-mcp is the account's primary device — fails with 'This command doesn't work on linked devices' if signal-mcp was set up via signal-cli link. Returns status 'device removed' and device_id. To only rename a device, use update_device.
| Name | Required | Description | Default |
|---|---|---|---|
| device_id | Yes | Device ID (get from list_devices) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint, idempotentHint and openWorldHint, so the safety profile is covered; the description goes further by disclosing the operational consequence (device immediately stops sending and receiving), the irreversibility of the unlink, and the exact failure mode ('This command doesn't work on linked devices') when signal-mcp was set up via signal-cli link.
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?
Dense but front-loaded — the destructive action and its consequence come first, then constraints, then return values, then the sibling alternative. Nearly every clause carries information, though the sentence count could be trimmed slightly.
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?
With no output schema, the description still states the return payload ('status' of 'device removed' plus device_id), covers the precondition, the failure case, and the alternative tool. Nothing needed to call it correctly is missing.
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 coverage is 100% so the baseline is 3, but the description adds real constraint meaning beyond the schema: device_id must reference a linked device and must not be 1 (the primary). That is a validation rule an agent cannot infer from the schema alone.
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?
States a specific verb and resource ('Permanently unlink a device from your Signal account') and immediately distinguishes itself from the three sibling device tools (list_devices, add_device, update_device). An agent can select it without opening any schema.
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?
Gives explicit when-to-use (permanent unlink), the alternative for the adjacent intent ('To only rename a device, use update_device'), and the recovery path (relink via add_device). It also names a hard precondition for calling it at all: signal-mcp must be the primary device.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_pinADestructiveIdempotent
Remove the Registration Lock PIN from your Signal account, so anyone who controls your phone number can re-register it without a PIN. No parameters. Primary device only: on a linked signal-cli setup it fails with 'This command doesn't work on linked devices'. Affects the real account immediately; undo it by calling set_pin again. Returns {status: 'PIN removed'}. Use set_pin to change the PIN instead of removing it.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as destructive, idempotent, not read-only, and open-world. The description adds valuable context beyond those hints: the exact failure on linked devices, the immediate account impact, and how to undo the operation by calling set_pin.
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, short, and every sentence carries useful information: purpose, effect, device constraint, undo path, return value, and alternative tool. No sentence is wasted.
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?
For a zero-parameter destructive tool, the description is complete: it covers the side effect, device limitation, undo path, return value, and the relevant alternative. Annotations cover the safety profile, and no output schema exists, so the stated return value is a useful addition.
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 takes zero parameters, so the baseline is 4. The description simply restates that there are no parameters, which matches the empty schema and adds no further parameter semantics.
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 states a specific verb and resource: removing the Registration Lock PIN from a Signal account. It also immediately distinguishes the effect from set_pin by noting that set_pin should be used to change the PIN instead of removing it.
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?
It gives explicit operational context: primary device only, linked-device failure mode, immediate real-account effect, and the alternative set_pin for changing rather than removing the PIN. This leaves little for the agent to infer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_scheduled_messagesA
Send every scheduled message whose send_at time has passed and is still pending. No parameters. Nothing else delivers scheduled messages, so call this (or run signal-mcp run-scheduled from cron) after their time; due messages are sent late, never dropped. Each due job is sent once as a real Signal message and marked 'sent' or 'failed' (failed jobs are not retried). Safe to call when nothing is due. Returns {processed: count, results: [{id, status: 'sent', timestamp} or {id, status: 'failed', error}]}. Use schedule_message to add jobs and list_scheduled_messages to inspect them.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnly=false, idempotent=false, destructive=false, openWorld=true. The description adds substantial context beyond that: due messages are sent late rather than dropped, each job is delivered once, failed jobs are not retried, it is safe to call when nothing is due, and the exact return shape. It is consistent with idempotentHint=false.
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?
Front-loads the core action in the first sentence, then layers delivery semantics, safety, return shape, and sibling routing. Every sentence carries distinct information; the dense return-value sentence is justified because there is no output schema.
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?
With zero parameters and no output schema, the description fully compensates by documenting retry behavior, the sent/failed status values, the returned fields, and safe no-op behavior. Nothing an agent needs to call it correctly is missing.
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 takes no parameters, and the description confirms 'No parameters,' so there is nothing to disambiguate. Per the rubric, zero params yields a baseline of 4.
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?
States a specific verb and resource ('send every scheduled message whose send_at time has passed and is still pending') and explicitly contrasts with the sibling tools schedule_message and list_scheduled_messages. An agent can distinguish this from the other scheduled-message tools without opening a schema.
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?
Gives explicit when-to-invoke guidance ('call this ... after their time'), names the cron alternative, states the prerequisite condition (send_at passed and pending), and routes to schedule_message / list_scheduled_messages for the other lifecycle stages. Exclusions are covered via the 'still pending' condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schedule_messageA
Save a text message in the local store to be sent at a future time. Give exactly one target: recipient (E.164 phone number, for a direct message) or group_id (for a group). message (required): the text. send_at (required): local time as 'YYYY-MM-DDTHH:MM[:SS]' or 'YYYY-MM-DD HH:MM[:SS]' (no timezone); must be in the future. Nothing is sent at that time by itself: a due message goes out only when run_scheduled_messages (or the signal-mcp run-scheduled CLI, e.g. from cron) runs. Returns {job_id, send_at, status: 'scheduled'}. Use list_scheduled_messages to review jobs and cancel_scheduled_message to cancel one; use send_message or send_group_message to send now.
| Name | Required | Description | Default |
|---|---|---|---|
| message | Yes | Message text to send | |
| send_at | Yes | When to send — ISO datetime string (e.g. '2024-06-01T09:00:00' or '2024-06-01 09:00') | |
| group_id | No | Group ID (for group messages). Mutually exclusive with recipient. | |
| recipient | No | Phone number in E.164 format (for DMs). Use group_id for group messages. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only record the write/non-idempotent/non-destructive profile; the description adds the critical behavior that nothing is actually sent at the scheduled time unless run_scheduled_messages (or the CLI) runs. It also discloses persistence to the local store and the exact return payload, which annotations cannot convey.
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 purpose and target rule are front-loaded, and the behavioral caveat and alternatives are grouped sensibly at the end. It is longer than strictly necessary ('message (required): the text' partly echoes the schema), but almost every sentence carries distinct, load-bearing information.
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?
With no output schema, the description compensates by stating the return shape {job_id, send_at, status}, the send-time dependency, and the target constraint. An agent has everything needed to schedule, review, and understand the deferred-send model.
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 coverage is 100%, so the baseline is 3, but the description adds genuine constraints beyond the schema: send_at is local time with no timezone, accepts two concrete formats, and 'must be in the future'. It also restates the mutually exclusive target rule with the E.164 requirement.
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 opens with a specific verb+resource+mechanism: 'Save a text message in the local store to be sent at a future time.' It explicitly distinguishes itself from immediate-send siblings by naming send_message and send_group_message as the 'send now' alternatives, so an agent can route correctly without opening any schema.
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?
It names the full lifecycle siblings and the condition that selects each: list_scheduled_messages to review, cancel_scheduled_message to cancel, send_message/send_group_message for immediate sending. It also states the target-selection rule ('exactly one target: recipient or group_id'), removing ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_messagesARead-onlyIdempotent
Full-text search of message bodies across all conversations in the local store (SQLite FTS; no Signal server call, nothing marked read). Only messages stored on this device are found. Use get_conversation to read a chat in order. query: words to find (all words must occur; falls back to substring match if FTS fails; empty returns []). sender: only messages from this E.164 number. since (inclusive) / until (exclusive) ISO dates, e.g. since=2024-01-01, until=2024-01-02 covers all of Jan 1; invalid dates return an error. limit: max results (default 50, clamped 1-500); offset: skip N results for paging (default 0). Returns a list of messages, newest first (id, sender, sender_name, recipient, group_id, group_name, body, timestamp, attachments …).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results to return (default 50, clamped 1-500) | |
| query | Yes | Keyword or phrase to search for | |
| since | No | Only messages at or after this ISO datetime (e.g. 2024-01-01 or 2024-01-01T09:00:00) | |
| until | No | Only messages strictly before this ISO datetime (exclusive; until=2024-01-02 includes all of Jan 1) | |
| offset | No | Skip this many results for pagination (default 0) | |
| sender | No | Filter results to messages from this phone number (E.164) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, closed-world), but the description adds substantial behavioral context beyond them: no Signal server call, nothing marked read, only locally stored messages are found, FTS failure falls back to substring matching, and invalid dates return an error. These are non-obvious traits an agent needs.
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?
Front-loaded with purpose then capabilities then per-parameter notes in one dense paragraph; every clause carries information. It does duplicate some schema details (date examples, limit clamp), which keeps it just short of ideal.
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?
No output schema exists, yet the description enumerates the returned fields (id, sender, sender_name, recipient, group_id, group_name, body, timestamp, attachments) and ordering (newest first), plus pagination and error behavior. An agent has everything needed to call and interpret it.
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 coverage is 100%, so the baseline is 3, but the description adds genuine meaning: multiple words must all occur (AND semantics not in the schema's 'keyword or phrase'), empty query returns [], and boundary examples for since/until. It repeats the limit clamping and date exclusivity already in 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?
States a specific verb (full-text search) and resource (message bodies) with a precise scope: 'across all conversations in the local store'. It explicitly distinguishes itself from get_conversation for reading a chat in order, so an agent can route without opening either schema.
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?
Names the alternative ('Use get_conversation to read a chat in order') and defines the boundary conditions: local device only, no server call, nothing marked read. The when-to-use and when-not-to-use conditions are both explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_attachmentA
Send one or more files (photos, videos, documents, audio) to one Signal contact in a single message. Use send_group_attachment for groups, send_message for text only, send_sticker for stickers. Address by recipient (E.164) or username (alice.42 or username link) — exactly one. path: a single file; paths: several files sent together (one of the two is required). Files must lie inside the allowed send folders (default: the signal-mcp attachments folder, ~/Downloads, ~/Desktop, ~/Documents; override with SIGNAL_MCP_SEND_ROOTS) and not be hidden, else an error is returned. caption: text shown with the files (default empty); view_once=true lets the recipient open media only once; voice_note=true marks audio as a voice note. Reply/quote: quote_author (E.164) + quote_timestamp (ms) of the original; quote_message (quoted text; default: looked up in the local store), quote_mentions ({start, length, author}), quote_text_styles ('start:length:STYLE') and quote_attachments ('contentType[:filename[:previewFile]]') only shape the quote bubble. no_urgent=true sends without a push notification; notify_self=true delivers a normal notifying message if you are among the recipients. Contacts Signal's servers; not idempotent (repeating sends a duplicate); sends share a 20-per-minute rate limit (calls wait rather than fail). Saved to the local store (caption as body). Returns {status, timestamp}.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Single file path (absolute, relative, or ~/path) | |
| paths | No | Multiple file paths to send as one message | |
| caption | No | Optional caption text shown below the attachment | |
| username | No | Signal username (e.g. alice.42) or username link, instead of recipient | |
| no_urgent | No | Send without the urgent flag, so the recipient gets no push notification | |
| recipient | No | Phone number in E.164 format | |
| view_once | No | Send as view-once media — recipient can only view it once before it disappears | |
| voice_note | No | Mark audio attachments as voice notes (played inline in Signal) | |
| notify_self | No | If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message | |
| quote_author | No | Phone number (E.164) of the author of the message being quoted/replied to | |
| quote_message | No | Text of the quoted message shown in the quote bubble. Default: looked up in the local store by quote_author + quote_timestamp | |
| quote_mentions | No | @mentions inside the quoted text, same shape as mentions: {start, length, author} | |
| quote_timestamp | No | Timestamp of the message being quoted/replied to (from get_conversation) | |
| quote_attachments | No | Attachments of the quoted message as 'contentType[:filename[:previewFile]]', e.g. 'image/png:photo.png' | |
| quote_text_styles | No | Styles inside the quoted text as 'start:length:STYLE' (BOLD, ITALIC, SPOILER, STRIKETHROUGH, MONOSPACE) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare a non-read-only, open-world, non-idempotent write, but the description adds substantial context beyond them: a 20-per-minute send rate limit where calls wait rather than fail, duplicate sends on repeat, errors for files outside allowed roots or hidden files, local-store persistence, and the return shape {status, timestamp}.
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 core action and alternatives, and its length is largely justified by 15 parameters. However, it is a dense single paragraph with semicolon-separated clauses, so structure could be improved for scanability.
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 high parameter count, absent output schema, and rich annotations, the description is complete enough: it covers purpose, alternatives, addressing, file constraints, behavioral caveats, rate limits, persistence, and return values. No critical calling information is missing.
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 coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: path and paths are mutually exclusive with one required, recipient and username are mutually exclusive, files must lie in allowed send folders, and quote fields only shape the quote bubble. The schema still carries most per-parameter detail, so this is not a full 5.
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 states a specific verb and resource: 'Send one or more files ... to one Signal contact in a single message.' It explicitly distinguishes this tool from send_group_attachment, send_message, and send_sticker, so an agent can route correctly without opening sibling schemas.
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?
It names the alternatives and the conditions that select them: use send_group_attachment for groups, send_message for text only, send_sticker for stickers. It also states addressing rules (recipient or username, exactly one) and file-source restrictions, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_contacts_syncAIdempotent
Send your local contact list to your other linked devices as a sync message, one-way from this device outward. Takes no parameters. Use it when contacts added or renamed through signal-mcp do not appear on your phone or desktop. Contacts no one else and changes nothing locally. Returns status 'contacts synced to linked devices'. To pull data from the primary device instead, use send_sync_request.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false but destructiveHint=false, which is ambiguous on its own; the description resolves this by clarifying it 'changes nothing locally' and 'contacts no one else,' and adds the one-way direction and the literal return value. That is real context beyond the structured hints.
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?
Front-loads what the tool does, then trigger, then side-effect profile, then return value, then alternative. Every sentence carries distinct information with no filler.
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?
There is no output schema, but the description states the exact return status ('contacts synced to linked devices'), covers side effects, directionality, and the alternative tool. Nothing needed to invoke it correctly is missing.
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?
Zero parameters, so the baseline is 4. The description reinforces this with 'Takes no parameters,' which is helpful but adds nothing the empty schema does not already imply.
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?
States a specific verb and resource (send contact list as a sync message) plus the direction of flow, 'one-way from this device outward.' It explicitly contrasts with the sibling send_sync_request, so an agent can distinguish it without opening schemas.
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?
Gives a concrete trigger condition ('when contacts added or renamed through signal-mcp do not appear on your phone or desktop') and names the alternative ('to pull data from the primary device instead, use send_sync_request'). This is explicit when-to-use plus alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_group_attachmentA
Send one or more files (photos, videos, documents, audio) to a Signal group in a single message. Use send_attachment for a single contact, send_group_message for text only. group_id comes from list_groups. path: a single file; paths: several files sent together (one of the two is required). Files must lie inside the allowed send folders (default: the signal-mcp attachments folder, ~/Downloads, ~/Desktop, ~/Documents; override with SIGNAL_MCP_SEND_ROOTS) and not be hidden, else an error is returned. caption: text shown with the files (default empty); view_once=true lets each member open media only once; voice_note=true marks audio as a voice note. Reply/quote: quote_author (E.164) + quote_timestamp (ms) of the original; quote_message (quoted text; default: looked up in the local store), quote_mentions ({start, length, author}), quote_text_styles ('start:length:STYLE') and quote_attachments ('contentType[:filename[:previewFile]]') only shape the quote bubble. no_urgent=true sends without a push notification; notify_self=true delivers a normal notifying message if you are among the recipients. Contacts Signal's servers; not idempotent (repeating sends a duplicate); sends share a 20-per-minute rate limit (calls wait rather than fail). Saved to the local store (caption as body). Returns {status, timestamp}.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Single file path (absolute, relative, or ~/path) | |
| paths | No | Multiple file paths to send as one message | |
| caption | No | Optional caption text shown below the attachment | |
| group_id | Yes | Group ID (get from list_groups) | |
| no_urgent | No | Send without the urgent flag, so the recipient gets no push notification | |
| view_once | No | Send as view-once media — each recipient can only view it once | |
| voice_note | No | Mark audio attachments as voice notes (played inline in Signal) | |
| notify_self | No | If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message | |
| quote_author | No | Phone number (E.164) of the author of the message being quoted/replied to | |
| quote_message | No | Text of the quoted message shown in the quote bubble. Default: looked up in the local store by quote_author + quote_timestamp | |
| quote_mentions | No | @mentions inside the quoted text, same shape as mentions: {start, length, author} | |
| quote_timestamp | No | Timestamp of the message being quoted/replied to (from get_conversation) | |
| quote_attachments | No | Attachments of the quoted message as 'contentType[:filename[:previewFile]]', e.g. 'image/png:photo.png' | |
| quote_text_styles | No | Styles inside the quoted text as 'start:length:STYLE' (BOLD, ITALIC, SPOILER, STRIKETHROUGH, MONOSPACE) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safety profile (readOnly=false, idempotent=false, openWorld=true), so the bar is lower, yet the description adds substantial context: sendable-folder restriction with default roots and env override, error on hidden files, contact with Signal servers, non-idempotency (duplicate sends), a 20/min shared rate limit that waits rather than fails, and store persistence.
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?
Front-loaded with purpose and sibling routing, then groups related concerns (files, caption/media flags, quoting, notification, side effects). It is dense and long, but with 14 parameters each clause carries information, so little is wasted.
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?
For a 14-parameter, non-idempotent mutation tool with no output schema, the description covers everything an agent needs: file constraints, flag semantics, quorum/quote behavior, side effects (server contact, rate limit, local store), and the return shape {status, timestamp}.
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 100%, so baseline is 3. The description goes beyond the schema by stating that path/paths are mutually exclusive with one required, and that quote_attachments/quote_text_styles/quotes only shape the quote bubble, but most parameter meaning is already documented in 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?
States a specific verb+resource+scope: 'Send one or more files ... to a Signal group in a single message.' It also explicitly distinguishes itself from send_attachment (single contact) and send_group_message (text only), so an agent can route without opening other schemas.
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?
Names the alternatives and the condition that selects each ('Use send_attachment for a single contact, send_group_message for text only') and points to list_groups for group_id. The file-root constraint further defines when a call will succeed vs. error.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_group_messageA
Send a text message to a Signal group (end-to-end encrypted to all members). Use send_message for a single contact, send_group_attachment for files. group_id comes from list_groups. message is the text. @mentions: put the name in the text and pass mentions [{start, length, author (E.164)}]; start/length are UTF-16 code units, not codepoints — an emoji before the mention shifts the offset by 2, not 1. formatting=true turns bold, italic, strikethrough, monospace and ||spoiler|| into real Signal formatting (markers are removed from the sent text); with it, mention offsets refer to the text as you wrote it, markers included, and are adjusted for you. Leave it off for text with literal asterisks or backticks. Reply/quote: quote_author (E.164) + quote_timestamp (ms) of the original; quote_message (quoted text; default: looked up in the local store), quote_mentions ({start, length, author}), quote_text_styles ('start:length:STYLE') and quote_attachments ('contentType[:filename[:previewFile]]') only shape the quote bubble. Link preview card: preview_url (must also appear in the text), preview_title (needed for the card to render), preview_description, preview_image (local file). Story reply: story_author (E.164, required with story_timestamp) + story_timestamp (ms). no_urgent=true sends without a push notification; notify_self=true delivers a normal notifying message if you are among the recipients. Contacts Signal's servers; not idempotent (repeating sends a duplicate); sends share a 20-per-minute rate limit (calls wait rather than fail). The sent message is saved to the local store. Returns {status, timestamp, group_id}; timestamp is the target_timestamp for edit_message, react_to_message or delete_group_message.
| Name | Required | Description | Default |
|---|---|---|---|
| message | Yes | Message text to send | |
| group_id | Yes | Group ID (from list_groups) | |
| mentions | No | List of @mentions. Each item: {start: offset of the mention in the message (UTF-16 code units, not codepoints), length: mention length (UTF-16 code units), author: E.164 phone number of the mentioned member}. Example: message='Hello @Alice', mentions=[{start:6,length:6,author:'+1234567890'}] | |
| no_urgent | No | Send without the urgent flag, so the recipient gets no push notification | |
| formatting | No | Convert **bold**, *italic*, ~~strikethrough~~, `monospace`, ||spoiler|| to Signal text formatting. Default false. | |
| notify_self | No | If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message | |
| preview_url | No | URL for a link preview card; the same URL must also appear in the message text | |
| quote_author | No | Phone number (E.164) of the author of the message being quoted/replied to | |
| story_author | No | Phone number of the story's author, to reply to a story | |
| preview_image | No | Local image file for the link preview thumbnail | |
| preview_title | No | Link preview title (needed for the card to render) | |
| quote_message | No | Text of the quoted message shown in the quote bubble. Default: looked up in the local store by quote_author + quote_timestamp | |
| quote_mentions | No | @mentions inside the quoted text, same shape as mentions: {start, length, author} | |
| quote_timestamp | No | Timestamp of the message being quoted/replied to (from get_conversation) | |
| story_timestamp | No | Timestamp of the story being replied to | |
| quote_attachments | No | Attachments of the quoted message as 'contentType[:filename[:previewFile]]', e.g. 'image/png:photo.png' | |
| quote_text_styles | No | Styles inside the quoted text as 'start:length:STYLE' (BOLD, ITALIC, SPOILER, STRIKETHROUGH, MONOSPACE) | |
| preview_description | No | Link preview description |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: discloses end-to-end encryption, that it contacts Signal's servers, that it is not idempotent (repeating sends a duplicate), a concrete 20-per-minute shared rate limit that makes calls wait rather than fail, local-store persistence, and the exact return shape {status, timestamp, group_id} with how timestamp feeds edit/react/delete. This is precisely the kind of destructive/write behavior context the annotations alone (idempotentHint=false, openWorldHint=true) cannot convey.
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?
Front-loads purpose and alternatives, then handles the complex optional behaviors; nearly every sentence carries information. It is, however, a single dense block for 18 parameters and would scan better as grouped bullets, and a few clauses (e.g., restating message/group_id) are slightly redundant with the schema.
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?
For a write tool with no output schema, the description supplies the return shape, side effects (persistence, duplicate-on-retry, rate limiting), and the full set of interaction paths (mentions, formatting, reply/quote, story reply, previews). Nothing needed to call it correctly appears to be missing.
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 100% schema coverage the baseline is 3, but the description adds real meaning: it explains that mention start/length are UTF-16 code units (with the concrete emoji-shifts-by-2 example) and that enabling formatting changes how offsets are interpreted and are auto-adjusted. It also clarifies that quote_* fields only shape the quote bubble and that preview_url must appear in the text, resolving non-obvious interactions the schema cannot express.
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?
States a specific verb and resource with scope: 'Send a text message to a Signal group (end-to-end encrypted to all members)'. It immediately differentiates from siblings by naming send_message for single contacts and send_group_attachment for files, so an agent can route correctly without opening any schema.
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 names alternatives and the conditions that select them (send_message for a contact, send_group_attachment for files). It also grounds required inputs (group_id from list_groups) and distinguishes the reply/quote path from the story-reply path, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_group_stickerA
Send one sticker from an installed sticker pack to a Signal group; it renders as a sticker, not a file. Use send_sticker for a single contact, send_group_attachment for ordinary images. group_id: from list_groups. pack_id: hex pack id and sticker_id: integer index within the pack, both from list_sticker_packs; an uninstalled pack or invalid id returns an error — install packs first with add_sticker_pack (signal.art URL). Contacts Signal's servers; not idempotent (repeating sends a duplicate); sends share a 20-per-minute rate limit (calls wait rather than fail). Saved locally as '[sticker pack:id]'. Returns {status, timestamp}.
| Name | Required | Description | Default |
|---|---|---|---|
| pack_id | Yes | Sticker pack ID (hex string from list_sticker_packs) | |
| group_id | Yes | Group ID (get from list_groups) | |
| sticker_id | Yes | Sticker ID within the pack (from list_sticker_packs) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-readOnly, openWorld, non-idempotent and non-destructive, but the description adds operational detail they don't carry: duplicate sends on repeat, a 20-per-minute shared rate limit where calls wait rather than fail, server contact, and local persistence as '[sticker pack:id]'. This is genuinely additive context beyond the structured hints.
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?
Dense but well front-loaded — the core action and the not-a-file behavior lead, followed by routing, parameter sourcing, side effects, and return shape. Slightly long, but nearly every clause carries distinct information.
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?
With no output schema, the description still gives the return shape {status, timestamp}, plus error conditions, rate-limit behavior, and persistence. For a 3-param mutating tool, an agent has everything needed to call it correctly and predict the outcome.
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 coverage is 100% and each param is self-documented, so baseline is 3. The description still adds value: it specifies pack_id is hex, sticker_id is an integer index within the pack, group_id comes from list_groups, and notes that an uninstalled pack or invalid id returns an error rather than silently failing.
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?
States a specific verb and resource ('send one sticker from an installed sticker pack to a Signal group') and explicitly disambiguates the outcome ('renders as a sticker, not a file'). It names the closest siblings (send_sticker, send_group_attachment) so an agent can route without opening schemas.
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 routes to send_sticker for single contacts and send_group_attachment for ordinary images, and adds the prerequisite path: install packs first with add_sticker_pack. Both when-to-use and the alternative-selection conditions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_messageA
Send a text message to one Signal contact (end-to-end encrypted). Use send_group_message for groups, send_attachment for files, send_note_to_self for your own Note to Self, schedule_message to send later. Address the contact by recipient (E.164, e.g. +4915112345678) or username (alice.42 or a username link) — exactly one, otherwise an error. message is the text; formatting=true turns bold, italic, strikethrough, monospace and ||spoiler|| into real Signal formatting (markers removed; leave off for literal asterisks/backticks). Reply/quote: quote_author (E.164) + quote_timestamp (ms) of the original; quote_message (quoted text; default: looked up in the local store), quote_mentions ({start, length, author}), quote_text_styles ('start:length:STYLE') and quote_attachments ('contentType[:filename[:previewFile]]') only shape the quote bubble. Link preview card: preview_url (must also appear in the text), preview_title (needed for the card to render), preview_description, preview_image (local file). Story reply: story_author (E.164, required with story_timestamp) + story_timestamp (ms). no_urgent=true sends without a push notification; notify_self=true delivers a normal notifying message if you are among the recipients. end_session=true instead resets the encrypted session (message ignored; troubleshooting only). Contacts Signal's servers; not idempotent (repeating sends a duplicate); sends share a 20-per-minute rate limit (calls wait rather than fail). The sent message is saved to the local store. Returns {status, timestamp, recipient}; timestamp is the target_timestamp for edit_message, react_to_message or delete_message.
| Name | Required | Description | Default |
|---|---|---|---|
| message | Yes | Message text to send | |
| username | No | Signal username (e.g. alice.42) or username link, instead of recipient | |
| no_urgent | No | Send without the urgent flag, so the recipient gets no push notification | |
| recipient | No | Phone number in E.164 format (e.g. +1234567890) | |
| formatting | No | Convert **bold**, *italic*, ~~strikethrough~~, `monospace`, ||spoiler|| to Signal text formatting. Default false. | |
| end_session | No | Reset the session with this contact instead of sending a message | |
| notify_self | No | If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message | |
| preview_url | No | URL for a link preview card; the same URL must also appear in the message text | |
| quote_author | No | Phone number (E.164) of the author of the message being quoted/replied to | |
| story_author | No | Phone number of the story's author, to reply to a story | |
| preview_image | No | Local image file for the link preview thumbnail | |
| preview_title | No | Link preview title (needed for the card to render) | |
| quote_message | No | Text of the quoted message shown in the quote bubble. Default: looked up in the local store by quote_author + quote_timestamp | |
| quote_mentions | No | @mentions inside the quoted text, same shape as mentions: {start, length, author} | |
| quote_timestamp | No | Timestamp of the message being quoted/replied to (from get_conversation) | |
| story_timestamp | No | Timestamp of the story being replied to | |
| quote_attachments | No | Attachments of the quoted message as 'contentType[:filename[:previewFile]]', e.g. 'image/png:photo.png' | |
| quote_text_styles | No | Styles inside the quoted text as 'start:length:STYLE' (BOLD, ITALIC, SPOILER, STRIKETHROUGH, MONOSPACE) | |
| preview_description | No | Link preview description |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly=false, openWorld=true, idempotent=false, destructive=false. The description goes further with operationally critical context the annotations cannot convey: a 20-per-minute shared rate limit where calls wait rather than fail, non-idempotent duplicates, local-store persistence, and the {status, timestamp, recipient} return (valuable since no output schema exists).
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?
Roughly 280 words for a 19-parameter tool, front-loaded with purpose and sibling routing before the parameter detail. Dense and mostly earn-its-place, though the mid-section reads as a run-on catalog of quote/preview fields that could be tightened with structure.
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 19 parameters, no output schema, and an outward-facing side-effecting call, the description covers safety-adjacent behavior (rate limits, duplicates, session reset, server contact), the return shape, and every non-obvious parameter interaction. Nothing an agent needs to call it correctly is missing.
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 coverage is already 100%, but the description adds cross-parameter semantics the schema omits: recipient/username mutual exclusivity with an error condition, quote_author+quote_timestamp pairing, story_author+story_timestamp mutual requirement, and 'preview_url must also appear in the text' / 'preview_title needed for the card to render'. This is genuine net-new meaning, not restatement.
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?
States a specific verb+resource+destination ('Send a text message to one Signal contact') and immediately distinguishes itself from send_group_message, send_attachment, send_note_to_self, and schedule_message. An agent can route to the right sibling without opening any schema.
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?
Explicit alternative routing is given for groups, files, Note to Self, and scheduled sends, plus the constraining condition 'exactly one, otherwise an error' for recipient/username. This is textbook when-to-use/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_message_request_responseAIdempotent
Accept or decline a message request from someone not in your contacts. sender (required, E.164) is who sent the request; accept (required): true accepts, which shares your profile with them; false declines (deletes the request) and turns profile sharing off. Declining does not block them — use block_contact for that. The decision is recorded locally and synced to your linked devices; the sender is not sent a message. Returns status 'message request accepted' or 'message request declined' and sender.
| Name | Required | Description | Default |
|---|---|---|---|
| accept | Yes | true to accept (shares your profile), false to decline (does not block) | |
| sender | Yes | Phone number (E.164) of the contact who sent the message request |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: accept shares your profile, decline deletes the request and turns profile sharing off, the decision is recorded locally and synced to linked devices, and no message is sent to the sender. This is unusually rich behavioral context for a mutating 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?
Front-loaded with the core action, then consequences, then the sibling disambiguation, then return values. Dense but every clause earns its place with no 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?
With no output schema, the description supplies the return values ('message request accepted'/'declined' plus sender). Side effects, device sync, and the non-blocking distinction are all covered, so nothing needed to call it correctly is missing.
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 100%, so the schema already documents both parameters (E.164 sender, accept semantics). The description restates this but adds little syntax or format detail beyond the schema, so the baseline 3 applies.
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?
States the specific verbs (accept/decline) and the exact resource (a message request from someone not in your contacts), which is distinct from every sibling. An agent can identify the operation without opening the schema.
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 routes the agent: declining 'does not block them — use block_contact for that,' naming the alternative and the condition that selects it. Both accept and decline outcomes are spelled out, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_note_to_selfA
Send a message to your own Note to Self chat; it syncs to all your linked Signal devices. Use for reminders, bookmarks or drafts; use send_message to message anyone else. message always supports bold, italic, strikethrough, monospace, ||spoiler|| (markers become Signal formatting) — e.g. a bold title per note. attachments: list of local file paths (e.g. a QR code); voice_note=true marks audio as a voice note. To thread a follow-up under an earlier note pass quote_author (your own number) + quote_timestamp (from a prior send_note_to_self result); quote_message, quote_mentions, quote_text_styles, quote_attachments optionally shape the quote bubble. Link preview card: preview_url (must also appear in the text), preview_title (needed for the card to render), preview_description, preview_image (local file). no_urgent=true sends without a push notification; notify_self=true delivers a normal notifying message if you are among the recipients. Combine content in one call rather than several. Not idempotent; shares the 20-sends-per-minute rate limit. Saved to the local store. Returns {status, timestamp}.
| Name | Required | Description | Default |
|---|---|---|---|
| message | Yes | Note text to save. Supports **bold**, *italic*, ~~strikethrough~~, `monospace`, ||spoiler|| | |
| no_urgent | No | Send without the urgent flag, so the recipient gets no push notification | |
| voice_note | No | Mark audio attachments as voice notes (played inline in Signal) | |
| attachments | No | File paths to attach (e.g. a QR code or screenshot) | |
| notify_self | No | If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message | |
| preview_url | No | URL for a link preview card; the same URL must also appear in the message text | |
| quote_author | No | Your own account number, to thread this note under a previous one | |
| preview_image | No | Local image file for the link preview thumbnail | |
| preview_title | No | Link preview title (needed for the card to render) | |
| quote_timestamp | No | Timestamp of the note being followed up on (from a prior send_note_to_self result) | |
| preview_description | No | Link preview description |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly=false, destructive=false, openWorld=true, idempotent=false), and the description adds real context beyond them: the 20-sends-per-minute rate limit, local-store persistence, syncing across linked devices, and the {status, timestamp} return shape. 'Not idempotent' merely restates the annotation, but the rate-limit and persistence details are genuine additions.
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?
Purpose and the key routing decision are front-loaded, and the dense sentences each carry distinct information (formatting, attachments, quoting, previews, notifications, rate limit). It is long for one description, but little is wasted.
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?
For an 11-parameter mutation tool, the definition covers routing, formatting, side effects (rate limit, local persistence), the return value, and quoting/link-preview mechanics. Nothing essential to a correct call is missing despite the absence of an output schema.
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 coverage is 100%, so the schema already documents all 11 parameters, and most of the description's per-parameter prose (preview_url must appear in text, preview_title needed to render, quote_author being your own number) duplicates it. It adds only marginal meaning, e.g. how quote_author plus quote_timestamp combine to thread a follow-up.
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?
States a precise verb and resource ('Send a message to your own Note to Self chat') and immediately distinguishes it from the sibling send_message. An agent can select it against send_message/send_group_message without opening a schema.
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 names the intended uses (reminders, bookmarks, drafts) and the alternative ('use send_message to message anyone else'). Guidance about combining content in one call also shapes invocation, so both when and how are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_read_receiptAIdempotent
Send a read receipt to a contact so their Signal app shows your messages as 'Read', and mark those messages read in the local store. Use after reading a DM with get_conversation (which marks read locally but sends no receipt). Not for groups. sender: E.164 number of the contact who sent the messages. timestamps: list of their messages' ms timestamps (the message id in get_conversation), batched in one call. Only shown if the sender has read receipts enabled. Contacts Signal's servers; repeating is harmless. Returns {status: 'read receipt sent'}.
| Name | Required | Description | Default |
|---|---|---|---|
| sender | Yes | Phone number (E.164) of the contact whose messages you are acknowledging | |
| timestamps | Yes | Millisecond timestamps of the messages to acknowledge (the message id in get_conversation) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly=false, openWorld=true, idempotent=true, destructive=false, and the description's 'Contacts Signal's servers; repeating is harmless' partly restates those. However it adds genuinely new behavior: it marks messages read in the local store, it is 'Only shown if the sender has read receipts enabled', and it returns {status: 'read receipt sent'}. These side-effect and conditional details go beyond the structured fields.
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?
Front-loaded with purpose, then usage, params, caveats, and return value in a logical order. Slightly long, and the server/idempotency sentence partially overlaps the annotations, but every sentence carries usable information.
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?
No output schema exists, yet the description supplies the return shape, the side effects, the recipient-side visibility condition, and full usage routing. An agent has everything needed to invoke it 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 coverage is 100%, so baseline is 3. The description adds real meaning beyond the schema: it clarifies that timestamps are the contact's message timestamps and should be 'batched in one call', and maps them to 'the message id in get_conversation', which the schema does not explain.
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?
States a specific verb and resource ('Send a read receipt to a contact') and immediately scopes it ('Not for groups'), distinguishing it from the many send_* siblings. It also names the related tool get_conversation, so the agent can place it precisely.
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?
Gives explicit when-to-use ('Use after reading a DM with get_conversation') including the reasoning (get_conversation marks read locally but sends no receipt), an explicit when-not ('Not for groups'), and the alternative context. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_stickerA
Send one sticker from an installed sticker pack to a single contact; it renders as a sticker, not a file. Use send_group_sticker for groups, send_attachment for ordinary images. recipient: E.164 number. pack_id: hex pack id and sticker_id: integer index within the pack, both from list_sticker_packs; an uninstalled pack or invalid id returns an error — install packs first with add_sticker_pack (signal.art URL). Contacts Signal's servers; not idempotent (repeating sends a duplicate); sends share a 20-per-minute rate limit (calls wait rather than fail). Saved locally as '[sticker pack:id]'. Returns {status, timestamp}.
| Name | Required | Description | Default |
|---|---|---|---|
| pack_id | Yes | Sticker pack ID (hex string from list_sticker_packs) | |
| recipient | Yes | Phone number in E.164 format | |
| sticker_id | Yes | Sticker ID within the pack (from list_sticker_packs) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=false, openWorldHint=true, so the safety profile is covered; the description goes well beyond by disclosing the 20-per-minute shared rate limit and that calls wait rather than fail, that sends contact Signal's servers, how the sticker is saved locally, and the error behavior on invalid pack/id. The non-idempotency restatement adds the concrete consequence (repeating sends a duplicate).
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?
Purpose and sibling routing are front-loaded in the first two clauses, and nearly every clause carries operational information. It is dense with semicolons and repeats parameter facts already at 100% schema coverage, so it is efficient rather than maximally tight.
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?
With no output schema, the description supplies the return shape ({status, timestamp}) and covers prerequisites, rate limiting, error cases, and side effects. Nothing an agent needs to call this correctly is missing.
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 coverage is 100%, so the baseline is 3, but the description adds real meaning: recipient must be E.164, pack_id is a hex id and sticker_id an integer index within the pack, both sourced from list_sticker_packs, plus the error semantics for invalid or uninstalled packs. It restates some schema content verbatim, which caps this below 5.
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?
States a specific verb (send), resource (sticker from an installed pack), and scope (one sticker, single contact), plus a clarifying contrast that it renders as a sticker rather than a file. It explicitly names the sibling tools it is not (send_group_sticker, send_attachment), so an agent can route without opening schemas.
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 when to use alternatives: send_group_sticker for groups, send_attachment for ordinary images. It also gives a prerequisite chain (install packs first with add_sticker_pack via signal.art URL) and the failure condition (uninstalled pack or invalid id returns an error).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_storyA
Post an image or video as a Signal story, visible to its audience for 24 hours. Use send_message / send_attachment to message someone directly. path: one local image or video file; Files must lie inside the allowed send folders (default: the signal-mcp attachments folder, ~/Downloads, ~/Desktop, ~/Documents; override with SIGNAL_MCP_SEND_ROOTS) and not be hidden, else an error is returned. group_id (from list_groups) posts to that group's story instead of My Story. allow_replies (default true): false disables replies. Contacts Signal's servers; not idempotent (each call posts a new story); shares the 20-sends-per-minute rate limit; not saved to the local store. Returns {status: 'posted', timestamp}.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Image or video file to post | |
| group_id | No | Post to this group's story instead of My Story (from list_groups) | |
| allow_replies | No | Allow viewers to reply (default: true) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover openWorld and non-idempotency, but the description adds substantially more: the 20-sends-per-minute rate limit, that the story is not saved to the local store, that files must lie within allowed send roots and not be hidden, and the exact return shape. These are behavioral traits beyond the structured fields.
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?
Purpose, alternatives and the path constraint are front-loaded, and the sentence flow mirrors call order. It is dense and slightly packed, but each clause (rate limit, local-store, non-idempotency, return value) earns its place.
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?
No output schema exists, yet the description supplies the return value ({status: 'posted', timestamp}), the visibility window, failure conditions (hidden file / outside roots) and rate-limit context. Nothing an agent needs to invoke it correctly is missing.
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 coverage is 100% (baseline 3), and the description still adds meaning beyond it: path is constrained to one local image/video inside allowed folders (with the env override), group_id must come from list_groups, and allow_replies=false disables replies. Adds real value over the terse schema descriptions.
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?
States a specific verb+resource ('Post an image or video as a Signal story') with scope (24-hour visibility) and immediately names the sibling tools it is not (send_message / send_attachment) for direct messaging. An agent can route between these without opening a schema.
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 names alternatives ('Use send_message / send_attachment to message someone directly') and the condition selecting the group variant ('group_id (from list_groups) posts to that group's story instead of My Story'). When-to-use and when-not logic is fully specified.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_sync_requestAIdempotent
Ask your primary Signal device to send this linked device its contacts, groups and settings. Takes no parameters. Use it when list_contacts or list_groups is missing entries that exist on your phone; it is meant for linked setups. Asynchronous: the call returns status 'sync requested' at once and the data arrives over the next seconds through the normal receive loop. It does not fetch new messages — use receive_messages for that. To push your contacts the other way, use send_contacts_sync.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, idempotentHint=true, destructiveHint=false), and the description adds real behavior beyond them: the call is asynchronous, returns status 'sync requested' immediately, and the data arrives through the normal receive loop. It stops short of describing failure modes or what happens if the primary device is offline.
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?
Front-loads the action, then delivery semantics, then routing alternatives. Every sentence carries distinct information; there is no repetition of the schema or annotations.
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?
No output schema exists, yet the description discloses the immediate return status and the later asynchronous arrival path, so an agent knows both what it gets back and what happens next. Complete for a zero-parameter trigger 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?
Zero parameters, which sets the baseline at 4 per the rubric. The description confirms 'Takes no parameters,' so nothing is left ambiguous.
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?
States a specific verb and resource ('Ask your primary Signal device to send this linked device its contacts, groups and settings') and explicitly separates itself from siblings like receive_messages and send_contacts_sync. An agent can identify the tool without opening the schema.
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?
Gives an explicit trigger ('when list_contacts or list_groups is missing entries that exist on your phone'), a scope constraint ('meant for linked setups'), an exclusion ('does not fetch new messages — use receive_messages'), and the reverse-direction alternative ('send_contacts_sync').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_expiration_timerAIdempotent
Set or turn off the disappearing-messages timer of a one-to-one or group chat. expiration_seconds (required): lifetime of new messages in seconds, 0 disables; common values 3600 (1h), 86400 (1d), 604800 (1w), 2592000 (30d). Pass recipient (E.164) for a direct chat or group_id (from list_groups) for a group; one is required, and group_id wins if both are given. Every participant is notified and the timer applies to new messages; already sent messages are unaffected. For a group this is the same as update_group with expiration_seconds. Returns status and seconds.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | No | Group ID (from list_groups) for a group conversation; wins if recipient is also given | |
| recipient | No | Phone number (E.164) for a direct conversation | |
| expiration_seconds | Yes | Timer in seconds (0 to disable). Common: 3600=1h, 86400=1d, 604800=1w |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (which only cover the safety/idempotency profile): it discloses that every participant is notified, that the timer applies only to new messages while already-sent messages are unaffected, and that the response contains status and seconds. These are non-obvious side effects an agent needs.
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?
A single dense paragraph that front-loads the action, then constraints, then side effects. Every clause carries information; slightly packed but not padded.
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?
No output schema exists, and the description compensates by stating the return ('status and seconds'). Addressing, disabling semantics, side effects, and the sibling equivalence are all covered, leaving nothing essential for correct invocation.
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 100% schema coverage the baseline is 3, but the description adds real value: the semantics of 0 (disable), a unit hint, a common-value table including 30d (2592000) which is absent from the schema, and the group_id-over-recipient precedence. It stops short of 5 only because most of this is a restatement plus modest additions.
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?
States a specific verb and resource: setting/disabling the disappearing-messages timer for a 1:1 or group chat. It distinguishes itself from neighbors by naming update_group as the equivalent path for groups, so an agent can route without opening another schema.
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?
Gives clear selection rules for its two addressing modes (recipient vs group_id, with group_id winning) and explicitly tells the agent that update_group with expiration_seconds is the equivalent operation. It lacks an explicit 'do not use when...' exclusion, which keeps it short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_pinAIdempotent
Set or replace the Registration Lock PIN on your Signal account, so re-registering your phone number elsewhere (e.g. after a SIM swap) requires this PIN. pin (string, required): the new PIN, numeric, e.g. '123456'. Primary device only: on a linked signal-cli setup it fails with 'This command doesn't work on linked devices'. Affects the real account immediately; calling again with a new pin replaces the old one. If you forget it, re-registration is blocked until the lock lapses after 7 days of inactivity. Returns {status: 'PIN set'}. Use remove_pin to turn the lock off; finish_change_number needs this PIN when changing numbers.
| Name | Required | Description | Default |
|---|---|---|---|
| pin | Yes | 4–20 digit numeric PIN (e.g. '123456') |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: states the effect is immediate on the real account, that re-calling replaces the old PIN, that it fails on linked devices, and the serious consequence of forgetting it (re-registration blocked until the lock lapses after 7 days). It also discloses the return payload {status: 'PIN set'}. This is exactly the additional context annotations cannot carry.
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?
Front-loaded with purpose, then constraints, consequences, return value, and sibling routing — each sentence earns its place. Slightly long and the PIN-format clause duplicates the schema, but no filler or padding.
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?
For a single-parameter mutation with no output schema, the description covers device requirements, idempotent replacement behavior, irreversibility/forgetting consequences, the return shape, and related tools. Nothing an agent needs to call it safely is missing.
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 coverage is 100% and the schema already documents the parameter as '4–20 digit numeric PIN (e.g. 123456)'. The description's 'numeric, e.g. 123456' adds nothing new and actually omits the 4–20 length range the schema provides. Baseline 3 for a fully-covered single parameter.
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?
States a specific verb+resource ('Set or replace the Registration Lock PIN on your Signal account') and disambiguates from the similarly named pin_message/unpin_message siblings by specifying the account-level Registration Lock. An agent can distinguish it from remove_pin and pin_message without opening any schema.
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 routes to alternatives: 'Use remove_pin to turn the lock off' and notes finish_change_number requires this PIN when changing numbers. It also gives a hard usage constraint ('Primary device only: on a linked signal-cli setup it fails'), which is exactly the when/when-not guidance an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_typingAIdempotent
Show or cancel the 'typing…' indicator in a DM or group. Purely cosmetic; use before send_message / send_group_message in an automated reply. recipient: E.164 number for a DM; group_id for a group (from list_groups); at least one is required. stop=true cancels an active indicator early (default false = start). The indicator expires by itself after ~15 seconds and is cleared when you send, so stop is rarely needed; one call per message is enough — don't loop. If the recipient disabled typing indicators it is silently ignored. Contacts Signal's servers; nothing is stored. Returns {status: 'typing indicator sent'}.
| Name | Required | Description | Default |
|---|---|---|---|
| stop | No | Set to true to cancel an active typing indicator (default: false = start typing) | |
| group_id | No | Group ID (base64) to show typing in a group | |
| recipient | No | Phone number in E.164 format |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safety profile (non-destructive, idempotent, open-world), and the description layers on non-obvious behavior: the indicator auto-expires in ~15s, is cleared on send, is silently ignored when the recipient has disabled indicators, contacts Signal's servers, and stores nothing. It even states the return value without an output schema.
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?
Front-loaded with the core purpose, then parameter semantics, then behavioral caveats and the return shape. Dense but every sentence carries operational information; nothing is redundant padding.
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?
For a small cosmetic tool with no output schema, the description covers purpose, parameter interpretation, lifecycle, edge cases, and the literal return payload. Nothing an agent needs to call it correctly is missing.
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 coverage is 100% so the baseline is 3, but the description adds meaning the schema lacks: it clarifies that recipient and group_id are alternatives ('at least one is required') even though the schema marks zero required params, and that group_id comes from list_groups. The '~15 second' expiry and silent-ignore behavior also disambiguate stop's value.
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?
States a specific verb ('show or cancel') plus the resource ('typing… indicator') and its scope (DM or group), which no sibling tool covers. An agent can distinguish it immediately from send_message/send_group_message without opening a schema.
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?
Gives explicit when-to-use guidance ('use before send_message / send_group_message in an automated reply'), an explicit when-not ('stop is rarely needed', 'one call per message is enough — don't loop'), and points to sibling tools by name. Routing is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_webhookAIdempotent
Save or clear the webhook URL that signal-mcp's background receiver (signal-mcp receive --watch, run by install-service) POSTs every incoming message to. url (optional): an http(s) URL such as 'http://localhost:5678/webhook/signal'; omit it or pass null/empty to clear. Stored in ~/.local/share/signal-mcp/webhook.json; the receiver reads it at startup, so restart the service for a change to apply. The SIGNAL_MCP_WEBHOOK environment variable overrides it. Payload: JSON {event: 'message', timestamp, sender, recipient, group_id, body, quote_id, attachments, is_read, receipt_type, expires_in_seconds, view_once}. Returns {status: 'webhook set', url} or {status: 'webhook cleared'}. Use get_webhook to check the value in effect.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | Webhook URL to POST to (e.g. 'http://localhost:5678/webhook/signal'). Omit or pass null to clear. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare mutating, idempotent, non-destructive. The description goes well beyond: storage path (~/.local/share/signal-mcp/webhook.json), that the receiver reads it only at startup, that SIGNAL_MCP_WEBHOOK overrides it, the exact JSON payload shape, and the two possible return objects.
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?
Front-loads the core action, then layers clearing semantics, storage/lifecycle, override behavior, payload and return shape. Dense but every sentence carries operational information; the payload field list is the only slightly expendable element.
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?
No output schema exists, yet the description spells out both return objects, the file it writes, the restart requirement, and the env-var override — everything needed to call it correctly and interpret the result.
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 coverage is 100% so the baseline is 3, but the description adds meaning the schema lacks: that an empty string (not just null/omission) also clears the webhook, plus the concrete localhost URL format used by the receiver.
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?
States a specific verb+resource: saving or clearing the webhook URL that signal-mcp's background receiver POSTs messages to. It names the sibling (get_webhook) that retrieves rather than mutates, so an agent can separate the two without opening a schema.
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 covers both branches: provide a URL to set, omit/null/empty to clear, and use get_webhook to inspect the effective value. It also names the operational precondition (restart the service for the change to apply).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_change_numberA
Step 1 of moving this Signal account to a new phone number: asks Signal to send a verification code to the new number. number (required): the new number in E.164 format, e.g. +12025551234; voice (boolean, default false): deliver the code by voice call instead of SMS; captcha (optional): a captcha token, needed only when a previous attempt failed with a captcha-required error; solve one at https://signalcaptchas.org/registration/generate.html and pass the resulting signalcaptcha:// token. Primary device only: on a linked signal-cli setup it fails with 'This command doesn't work on linked devices'. The account stays on the old number until finish_change_number succeeds. Rate limits are returned as errors. Returns {status: 'verification code sent', number}. Then call finish_change_number with the same number and the received code.
| Name | Required | Description | Default |
|---|---|---|---|
| voice | No | Request code via voice call instead of SMS (default: false) | |
| number | Yes | New phone number in E.164 format (e.g. +12025551234) | |
| captcha | No | Captcha token (required only if Signal demands it) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, idempotentHint=false, destructiveHint=false, openWorldHint=true) by disclosing that the account stays on the old number until finish_change_number succeeds, that rate limits surface as errors, that linked devices will fail with a specific message, and the exact return payload.
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?
Information-dense and front-loaded with the purpose, then constraints, then next step. It is a long single block with semicolon-chained parameter notes, which slightly hurts scannability, but nearly every clause carries load-bearing detail.
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?
With no output schema, the description supplies the return shape ({status: 'verification code sent', number}) and the full two-step workflow, device prerequisites, and error conditions. An agent has everything needed to invoke and sequence this 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 coverage is already 100%, but the description adds real meaning on top: the captcha token is only needed after a captcha-required error, plus the URL to mint one and the signalcaptcha:// token format — operational detail absent from 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?
Opens with a precise verb+resource: 'Step 1 of moving this Signal account to a new phone number: asks Signal to send a verification code to the new number.' It explicitly positions itself as the first half of a two-step flow, making it distinguishable from the sibling finish_change_number.
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?
States when to call it, names the follow-up call ('Then call finish_change_number with the same number and the received code'), and gives explicit exclusions: primary device only, fails on linked signal-cli setups. The captcha branch is conditioned on a specific prior error.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
store_statsARead-onlyIdempotent
Report statistics about signal-mcp's local message database (~/.local/share/signal-mcp/messages.db). Returns {total_messages, unread_messages (incoming only), db_size_bytes, oldest, newest} with oldest/newest as ISO datetimes or null when empty. Read-only, local only, no daemon needed. Use it to check whether history has been imported (import_desktop / sync_desktop) or before cleaning up with prune_store, delete_local_messages or clear_local_store.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description adds real context beyond that: local-only, no daemon required, the on-disk path, and the semantics that unread counts incoming messages only and oldest/newest are null when the store is empty.
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?
Three sentences: purpose, return contract, then usage routing. Front-loaded and every sentence earns its place with no 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?
With no output schema, the description carries the return-value burden and does so fully — it names every field and the null semantics. Combined with the annotations and zero parameters, an agent has everything needed to call it 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 tool takes no parameters, so per the rubric the baseline is 4. The description correctly spends no space on parameter syntax and instead documents the return shape, which is the useful information here.
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?
States a specific verb and resource ('Report statistics about signal-mcp's local message database') and even names the exact DB path. It enumerates the returned fields, so an agent knows precisely what it produces and can distinguish it from siblings like get_unread or list_conversations.
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?
Gives explicit when-to-use conditions: verify history import status before/after import_desktop or sync_desktop, and check store state before destructive cleanup via prune_store, delete_local_messages or clear_local_store. Both the alternatives and the selecting conditions are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_rate_limit_challengeA
Lift a Signal rate limit on sending by submitting a proof-of-humanity challenge. Use it when a send fails with a rate-limit / proof-required error that includes a challenge token. challenge (required): the challenge token from that error; captcha (required): the token from solving the captcha at https://signalcaptchas.org/challenge/generate.html. Talks to Signal's servers; a rejected captcha returns an error and you need a fresh one. Returns {status: 'challenge submitted'}; then retry the failed send. For a captcha needed while changing number, pass it to start_change_number instead.
| Name | Required | Description | Default |
|---|---|---|---|
| captcha | Yes | Solved captcha token from the Signal captcha page | |
| challenge | Yes | Challenge token from the rate-limit error |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag openWorldHint=true and idempotentHint=false, and the description reinforces the external call ('Talks to Signal's servers') while adding behavior annotations do not carry: a rejected captcha returns an error and requires a fresh one, and the caller must retry the failed send afterward. Error and retry semantics are precisely the value-add expected here.
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?
Front-loads the purpose, then trigger, then parameters, then error behavior and return value, then the sibling alternative. Every sentence carries load with no filler; parentheticals are compact.
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?
No output schema exists, but the description discloses the return value ({status: 'challenge submitted'}) and the required follow-up action (retry the failed send), plus failure behavior. For a two-parameter, single-purpose tool this leaves nothing an agent needs missing.
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 coverage is 100%, so the baseline is 3, but the description goes beyond the schema by stating where each token originates: the challenge token 'from that error' and the captcha token from solving the captcha at a specific URL. That origin/provenance detail is genuinely useful for correct invocation.
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?
States a specific verb+resource ('Lift a Signal rate limit on sending') and the mechanism (submitting a proof-of-humanity challenge), which no sibling tool offers. An agent can immediately tell this apart from send_message or start_change_number.
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?
Gives an explicit trigger ('when a send fails with a rate-limit / proof-required error that includes a challenge token') and an explicit exclusion/alternative ('For a captcha needed while changing number, pass it to start_change_number instead'). This is exactly the when/when-not/alternative guidance the dimension rewards.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sync_desktopAIdempotent
Incrementally import new messages from Signal Desktop into signal-mcp's local store: only messages newer than the last sync (with a 60-second overlap) are read, so repeat calls are fast. No parameters. The first call imports everything, like import_desktop. Same requirements as import_desktop: sqlcipher, Signal Desktop installed, and Keychain (macOS) or secret-tool (Linux) access to its key. Only writes to the local store; duplicates are skipped. Returns the import_desktop fields {imported, skipped, total, max_ts_ms, platform, source} plus since (ISO datetime of the lower bound, null on first run) and incremental (boolean). Use import_desktop only for a deliberate full re-scan.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already disclose the safety profile (readOnlyHint=false, idempotentHint=true, destructiveHint=false, openWorldHint=false), and the description adds valuable context beyond them: only writes to the local store, duplicates are skipped, a 60-second overlap is used, first-run behavior is described, and external prerequisites are listed. It also describes return fields including since and incremental, so behavior is unusually 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 dense but front-loaded with the core incremental-import behavior, then adds requirements, side effects, and return shape in a logical order. Every sentence carries useful operational information and none is redundant.
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 lack of an output schema, the description compensates by naming the returned fields and their meaning, including since and incremental. It also covers prerequisites, local-write-only behavior, and the relationship to import_desktop, leaving no major gap for correct invocation.
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, so there is no parameter schema to interpret; the description explicitly states 'No parameters,' which is appropriate. This meets the baseline for a parameterless tool and adds no misleading detail.
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 states a specific verb and resource ('Incrementally import new messages from Signal Desktop into signal-mcp's local store') and immediately distinguishes the operation from import_desktop by emphasizing incremental scope. An agent can identify what the tool does and how it differs from its closest sibling without opening any schema.
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?
It gives explicit when-to-use context: repeat calls are fast because only messages newer than the last sync are read, while the first call imports everything like import_desktop. It also gives a direct alternative rule: 'Use import_desktop only for a deliberate full re-scan.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
terminate_groupADestructiveIdempotent
DESTRUCTIVE AND IRREVERSIBLE: permanently terminate a Signal group FOR ALL MEMBERS; afterwards nobody can send messages or start calls in it. Requires admin rights. To just exit the group yourself, use leave_group. group_id (required, from list_groups). confirm (required) must be true, otherwise nothing happens and an error is returned; only set it after the user explicitly asked to end the group for everyone. Returns status and group_id.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | Yes | Must be true to proceed — prevents accidental termination | |
| group_id | Yes | Group ID to terminate (get from list_groups) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint/readOnlyHint, but the description goes well beyond them: irreversible permanence, effect on all members, inability to send messages or start calls afterward, admin-rights requirement, and the exact behavior of the confirm gate (no-op plus error if not true). This is rich behavioral context the annotations do not carry.
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?
Front-loaded with the DESTRUCTIVE AND IRREVERSIBLE warning, then prerequisites, then the sibling alternative, then parameter semantics. Dense but every clause earns its place with no 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?
For a destructive mutation tool with no output schema, the description covers consequences, authorization, the confirmation gate, the alternative sibling, and even the return shape (status and group_id). Nothing an agent needs to call it safely is missing.
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 coverage is 100%, so the baseline is 3, but the description adds value: it ties group_id to list_groups and, more importantly, defines the policy for confirm (must be true, otherwise nothing happens and an error is returned; only set after an explicit user request). That goes beyond the schema's generic 'prevents accidental termination'.
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?
States a specific verb (terminate) and resource (Signal group), plus scope (FOR ALL MEMBERS), and explicitly contrasts with the sibling leave_group. An agent can distinguish it from leave_group, update_group, and delete_message without opening any schema.
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?
Explicit when-to-use (end the group for everyone, requires admin rights), when-not (use leave_group to exit yourself), and a policy constraint that confirm should only be set after the user explicitly asked. Alternatives and exclusions are named outright.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
terminate_pollADestructive
Close a poll you created so no more votes are accepted; participants see it as ended with final results. Irreversible. Use vote_poll to vote, create_poll to start a new one. Only the creator can terminate. target_author: your own E.164 number (accepted for symmetry with vote_poll; only the timestamp is sent); target_timestamp: ms timestamp of the poll (from create_poll or get_conversation). Give recipient (E.164) for a DM poll or group_id for a group poll; neither is an error. Contacts Signal's servers. Returns {status: 'poll terminated'}.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | No | Group ID for a group poll — provide this OR recipient | |
| recipient | No | Phone number for a DM poll — provide this OR group_id | |
| target_author | Yes | Phone number of the poll creator — must be your own number | |
| target_timestamp | Yes | Timestamp of the poll message (from get_conversation) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=false, so the safety profile is covered. The description adds real context beyond that: the action is irreversible, participants see final results, only the creator may act, and the call contacts Signal's servers. Strong additive disclosure, though the remote side-effect story could be marginally richer.
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?
Front-loaded with the action and its irreversibility, then routing, then parameter notes, then the return value. Slightly dense but every sentence carries information an agent needs; no filler sentences.
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?
With no output schema, the description supplies the return shape ({status: 'poll terminated'}), the permission constraint, and the DM-vs-group addressing rule. For a destructive 4-parameter tool this covers everything needed to call it 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 coverage is 100%, so the baseline is 3, but the description goes beyond the schema by explaining the odd target_author semantics ('accepted for symmetry with vote_poll; only the timestamp is sent'), the source of target_timestamp (create_poll or get_conversation), and that supplying neither recipient nor group_id is not an error.
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?
States a specific verb (terminate) and resource (poll) with the scope of the effect: closing a poll you created so no more votes are accepted. It explicitly distinguishes itself from the two closest siblings, vote_poll and create_poll, so an agent can route correctly without reading either schema.
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?
Gives explicit alternates with conditions ('Use vote_poll to vote, create_poll to start a new one') and a hard precondition ('Only the creator can terminate'). Nothing about when to choose this tool is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
trust_identityAIdempotent
Mark a contact's identity key as trusted so sending to them works again after their safety number changed (e.g. they reinstalled Signal). number (required, E.164). safety_number (optional): the safety number or fingerprint you verified in person or by call, as shown by list_identities; only that key is trusted and it becomes TRUSTED_VERIFIED. Without safety_number ALL known keys for the number are trusted unverified — this unblocks delivery but skips verification, so prefer passing it. Changes local trust only; the contact is not notified. Fails if the number or safety number does not match. Returns status 'trusted' and number.
| Name | Required | Description | Default |
|---|---|---|---|
| number | Yes | Phone number (E.164) whose identity key to trust | |
| safety_number | No | Safety number or fingerprint you verified (from list_identities); omit to trust all known keys unverified |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, idempotentHint=true, destructiveHint=false), the description discloses that trust is local-only, the contact is not notified, the call fails on mismatch, and it returns status 'trusted' plus the number. It also explains the state difference between the verified and unverified paths (TRUSTED_VERIFIED vs unverified), which annotations cannot convey.
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?
Dense and front-loaded: purpose and trigger first, then parameter semantics, then side effects and return. Every sentence carries information, though it is a single long paragraph that could be broken up for faster scanning.
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?
For a 2-parameter mutation with no output schema, it covers prerequisites (verification via list_identities), failure modes, side effects, and return values. Nothing an agent needs to call it correctly is missing.
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 coverage is already 100%, yet the description adds real meaning: E.164 format, that safety_number scopes trust to only that key and yields TRUSTED_VERIFIED, and that omitting it trusts ALL known keys unverified. That consequence-of-omission detail is not derivable from 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?
States a precise verb+resource ('Mark a contact's identity key as trusted') and the exact condition that motivates it (safety number changed, e.g. reinstall). It is clearly distinguishable from sibling tools like list_identities, which it names as the source of the safety number.
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 when to use it (to restore sending after a safety number change), when to prefer the verified path ('prefer passing it'), and what the fallback does. It also names the upstream tool (list_identities) the agent should consult first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unblock_contactAIdempotent
Unblock a previously blocked contact so their messages and calls reach you again. number (required, E.164). Only works when signal-mcp is the account's primary device — fails with 'This command doesn't work on linked devices' if signal-mcp was set up via signal-cli link. The contact is not notified; unblocking also accepts their message request (your profile is shared with them again) and syncs to your linked devices. Unblocking a contact that is not blocked is a no-op. Use list_contacts with blocked=true to see who is blocked, block_contact to block again. Returns status 'unblocked' and number.
| Name | Required | Description | Default |
|---|---|---|---|
| number | Yes | Phone number to unblock (E.164 format) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations give the safety profile (non-readOnly, non-destructive, idempotent, open-world), and the description adds substantial context beyond them: the primary-device prerequisite and its exact failure mode, that the contact is not notified, that unblocking accepts their message request and re-shares the profile, and that changes sync to linked devices.
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?
Front-loaded with the core action and effect, then the prerequisites and side effects. Dense but every sentence carries information; the only mild cost is that the caveats are packed into one long paragraph.
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?
No output schema exists, but the description supplies the return value ('status unblocked and number'), the failure mode, the side effects, and the alternatives. An agent has everything needed to invoke and interpret it.
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?
Only one parameter and schema coverage is 100%, so the schema already documents 'number (E.164 format)'. The description reinforces the E.164 requirement but adds no syntax beyond that, which is appropriate for a single-param tool.
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?
States a specific verb (unblock) and resource (contact) plus the immediate effect ('so their messages and calls reach you again'). It is clearly distinguished from its sibling block_contact, which it names directly.
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 routes the agent: use list_contacts with blocked=true to find blocked contacts, block_contact to reverse the action. It also states the no-op case for unblocking a non-blocked contact, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unpin_messageAIdempotent
Remove a pinned message from the top of a DM or group conversation for all participants; the message itself stays. Use pin_message to pin. target_author: E.164 number of the pinned message's sender; target_timestamp: its ms timestamp (message id in get_conversation). Give recipient (E.164) for a DM or group_id for a group; neither is an error. Contacts Signal's servers; repeating has no further effect. Returns {status: 'message unpinned'}.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | No | Group ID for group conversations — provide this OR recipient | |
| recipient | No | Phone number for DM conversations — provide this OR group_id | |
| target_author | Yes | Phone number of the message author (E.164) | |
| target_timestamp | Yes | Timestamp of the pinned message (from get_conversation) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds real behavioral context beyond annotations: 'the message itself stays' clarifies non-destructive scope, 'for all participants' states the effect's reach, 'Contacts Signal's servers' matches openWorldHint, and 'repeating has no further effect' explains the idempotentHint. The idempotency point overlaps the annotation but is explained rather than merely repeated.
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?
Front-loaded with the purpose, then packed into a compact semicolon-delimited sentence carrying routing rules and the return value. Dense but every clause carries information; no filler.
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?
For a mutation with no output schema, the description covers effect scope, non-destructiveness, server contact, idempotency, and even the return value {status: 'message unpinned'}. Only auth/permission prerequisites are unaddressed, a minor gap given the annotation profile.
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 coverage is 100%, so the schema already documents all four parameters, including E.164 format and get_conversation provenance. The description mostly restates these ('E.164 number', 'its ms timestamp (message id in get_conversation)'), adding only the 'ms' unit precision, so baseline 3 applies.
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?
States a specific verb+resource ('Remove a pinned message from the top of a DM or group conversation for all participants') and clarifies the message itself is preserved. It names pin_message as the inverse but does not differentiate from the sibling remove_pin, leaving a small ambiguity about which removal tool applies.
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 routes to pin_message for the opposite operation and tells the agent the conversation-selector rule ('Give recipient for a DM or group_id for a group'), so context is clear. No when-not guidance and no mention of remove_pin, so it falls short of full alternative coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_accountADestructiveIdempotent
Change account attributes stored on Signal's servers for this account. All six parameters are optional and only the ones you pass are sent: device_name (string) renames this device as shown in list_devices on your other devices; discoverable_by_number (boolean) whether people who have your number can find you on Signal; number_sharing (boolean) whether your phone number is shown to people you message; unrestricted_unidentified_sender (boolean) true lets anyone, not only contacts, send you sealed-sender messages; username (string, without @) claims a Signal username; delete_username (boolean) removes the current one and takes precedence over username if both are given. Takes effect immediately on the real account; setting a username that is taken or invalid fails with an error. Returns {status: 'account updated'} (the resulting username is not echoed). Use update_configuration for read receipts, typing indicators and link previews, update_profile for your name, about text and avatar.
| Name | Required | Description | Default |
|---|---|---|---|
| username | No | Set a Signal username (without @) as an alias for your number | |
| device_name | No | Name for this device shown in linked devices list | |
| number_sharing | No | Share your phone number when sending messages | |
| delete_username | No | Delete your current Signal username | |
| discoverable_by_number | No | Allow others to find your account by phone number | |
| unrestricted_unidentified_sender | No | Allow sealed-sender messages from anyone (not just contacts) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (destructiveHint=true, idempotentHint=true), and the description adds substantial context beyond them: changes take effect immediately on the real account, invalid/taken usernames fail with an error, delete_username takes precedence over username, and the return payload is {status: 'account updated'} with the username not echoed.
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 purpose and the alternative-tool routing are front-loaded, and every sentence carries information. It is, however, a dense unbroken block rather than a structured parameter list, which slightly hurts scanability for a six-parameter tool.
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 no output schema, the description states the exact return shape and the notable omission (username not echoed), covers error behavior, precedence, and cross-tool routing. Nothing an agent needs to call this correctly is missing.
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 coverage is 100%, so baseline is 3, but the description goes further: it explains what each flag means in user terms (device_name appears in list_devices on other devices; discoverable_by_number governs number-based discovery), specifies the username format (without @), and documents the delete_username-over-username precedence rule that the schema does not.
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?
States a specific verb and resource ('Change account attributes stored on Signal's servers for this account') and explicitly routes the agent away from siblings: update_configuration for receipts/typing/link previews and update_profile for name/about/avatar. An agent can distinguish it from every related tool without opening a schema.
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?
Names the two alternatives and the exact conditions that select them, plus notes that all six parameters are optional and only passed ones are sent. This tells the agent both when to use this tool and when to use a neighbor instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_configurationAIdempotent
Change account-wide messaging settings and sync them to your linked devices. All four booleans are optional; omit any you do not want to change, and a call with none is a no-op: read_receipts whether senders are told when you have read their messages; typing_indicators whether contacts see you typing; link_previews whether URLs in outgoing messages get previews; unidentified_delivery_indicators whether sealed-sender delivery icons are shown. Primary device only: on a linked signal-cli setup it fails with 'This command doesn't work on linked devices'. Returns {status: 'updated'}. signal-cli cannot read the current values back, so track what you set. Use update_account for discoverability, number sharing and username; update_profile for name and avatar.
| Name | Required | Description | Default |
|---|---|---|---|
| link_previews | No | Enable/disable link previews in messages | |
| read_receipts | No | Enable/disable sending read receipts | |
| typing_indicators | No | Enable/disable sending typing indicators | |
| unidentified_delivery_indicators | No | Show/hide sealed sender indicators |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing linked-device sync, the exact failure mode on linked signal-cli setups, the no-op behavior, the return value ({status: 'updated'}), and the fact that current values cannot be read back so callers must track state. The idempotentHint/destructiveHint annotations don't cover any of this operational context.
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?
Front-loads the core action and scope, then elaborates each boolean and the constraints. Dense and mostly waste-free, though the per-boolean clarifications and routing notes make it longer than strictly necessary.
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?
For a no-required-param mutation tool, it covers scope, optionality, failure modes, return value, and sibling routing, leaving nothing an agent needs to call it correctly. No output schema exists, yet the return shape is still disclosed.
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 coverage is 100%, so the baseline is 3, but the description adds real meaning over the terse schema text — e.g. 'read_receipts whether senders are told when you have read their messages' and the sealed-sender explanation for unidentified_delivery_indicators. It also reinforces optionality, which the schema does not state.
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?
States a specific verb+resource ('Change account-wide messaging settings') and scopes it to the four booleans it mutates. It explicitly differentiates from siblings update_account and update_profile by naming the settings each one handles.
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 explains optionality ('omit any you do not want to change'), the no-op case, the primary-device-only constraint, and precisely when to reach for update_account vs update_profile instead. An agent needs no inference to choose correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_contactAIdempotent
Set your private local name, nickname or note for another contact; it is synced to your own linked devices and never shown to the contact. To change your own public profile use update_profile; to block or delete a contact use block_contact or remove_contact. number (required, E.164). Pass at least one of: name (full display name; stored as given name and clears the family name unless family_name is also given), given_name, family_name, nick_given_name, nick_family_name (nickname shown instead of their profile name), note (private note). Fails if none is given or the number is not registered on Signal. Returns status, number and name. For a disappearing-message timer use set_expiration_timer.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Display name to set | |
| note | No | Private note about the contact | |
| number | Yes | Phone number in E.164 format | |
| given_name | No | Contact given name | |
| family_name | No | Contact family name | |
| nick_given_name | No | Nickname given name | |
| nick_family_name | No | Nickname family name |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnly=false, destructive=false, idempotent=true), and the description adds non-obvious behavior on top: the change is local-only, synced to your linked devices, never visible to the contact, and setting 'name' silently clears family_name unless family_name is also supplied. That side-effect disclosure is exactly the kind of trait structured fields cannot convey.
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?
Front-loaded with the core purpose and alternatives, and every sentence carries information. Slightly dense with nested parentheticals in the parameter list, but appropriate for a 7-parameter tool in a crowded sibling namespace.
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?
With no output schema, the description supplies the return shape ('status, number and name'), the failure modes, the exclusivity constraint, and the local-only scope. Nothing needed to invoke it correctly is missing.
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 coverage is 100% (baseline 3), but the description goes well beyond it: it supplies the E.164 format, the cross-field rule that at least one optional field must be passed, and semantic distinctions the schema lacks (name vs. given/family name interaction, nickname 'shown instead of their profile name').
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?
States a specific verb (set) and resource (private local name/nickname/note for another contact) and immediately contrasts it with update_profile, block_contact and remove_contact. An agent can distinguish it from every nearby sibling without opening a schema.
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 routes alternatives: update_profile for your own public profile, block_contact/remove_contact for blocking or deleting, set_expiration_timer for timers. It also states the precondition ('Pass at least one of...') and two failure conditions (no field given, number not registered).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_deviceAIdempotent
Rename a device on your Signal account; the name shows in every device's Linked Devices list. device_id (required, integer from list_devices); name (required): the new label. Renaming the device signal-mcp itself runs on works everywhere; renaming any other device only works when signal-mcp is the account's primary device — otherwise it fails with 'This command doesn't work on linked devices'. Does not affect messaging. Returns status, device_id and name. To unlink a device use remove_device; to change your profile name use update_profile.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | New display name for the device | |
| device_id | Yes | Device ID (get from list_devices) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, idempotentHint=true, destructiveHint=false, openWorldHint=true) by disclosing the side effect (visible in every device's Linked Devices list), the primary-device precondition for renaming other devices, that messaging is unaffected, and the returned fields (status, device_id, name).
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?
Front-loaded with purpose, then precondition, then scope note and alternatives in a tight sequence with no filler. It is dense and slightly long, but nearly every clause carries actionable information (the quoted error string is the only borderline item).
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?
For a two-parameter mutation with no output schema, the description covers purpose, precondition, failure mode, side effects, and return fields, and routes to alternatives. Nothing an agent needs in order to call it correctly is missing.
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 100%, so both parameters are already documented. The description restates device_id as coming from list_devices and name as the new label, adding only marginal context beyond the schema, so the baseline 3 applies.
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?
States a specific verb+resource ('Rename a device on your Signal account') and immediately scopes what the name affects (the Linked Devices list on every device). It is clearly distinguishable from siblings like update_profile or remove_device, which it names explicitly.
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?
Gives explicit routing: use remove_device to unlink, use update_profile to change profile name. It also states the precise precondition under which the tool works versus fails, including the exact error text 'This command doesn't work on linked devices'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_groupADestructiveIdempotent
Change an existing group's details, membership, admins, invite link, permissions or timer; only the fields you pass change. group_id (required, from list_groups). name, description: new text. avatar: local image path inside the allowed send folders. add_members / remove_members / add_admins / remove_admins / ban_members / unban_members: lists of E.164 numbers. expiration_seconds: disappearing-message timer, 0 disables. link_mode: 'enabled' (anyone with the link joins), 'enabled-with-approval', 'disabled', or 'reset' (same as reset_link=true, which issues a new link and invalidates the old one). permission_add_member, permission_edit_details, permission_send_messages: 'every-member' or 'only-admins' (only-admins sending = announcement group). member_label / member_label_emoji set ONLY YOUR OWN label in this group (the tag next to your name); you cannot set another member's label. Changes apply immediately and every member gets a group update; removals and bans are not undone automatically. Admin rights are needed for most changes, depending on the group's permissions. Returns status and group_id. Use send_group_message to post, leave_group to exit.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | New group name | |
| avatar | No | Local image file path for the new group avatar (must be inside the allowed send folders) | |
| group_id | Yes | Group ID to update (get from list_groups) | |
| link_mode | No | Invite link mode: 'disabled', 'enabled', 'enabled-with-approval', or 'reset' to generate a new link | |
| add_admins | No | Phone numbers (E.164) to promote to admin | |
| reset_link | No | Generate a new invite link, invalidating the old one | |
| add_members | No | Phone numbers (E.164) to add | |
| ban_members | No | Phone numbers (E.164) to ban from (re)joining the group | |
| description | No | New group description | |
| member_label | No | YOUR OWN member label in this group (not other members') | |
| remove_admins | No | Phone numbers (E.164) to demote from admin | |
| unban_members | No | Phone numbers (E.164) to remove from the ban list | |
| remove_members | No | Phone numbers (E.164) to remove | |
| expiration_seconds | No | Disappearing message timer in seconds (0 to disable) | |
| member_label_emoji | No | Emoji for YOUR OWN member label | |
| permission_add_member | No | Who may add new members | |
| permission_edit_details | No | Who may edit group name, description, avatar, timer | |
| permission_send_messages | No | Who may send messages ('only-admins' = announcement group) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as a destructive, non-read-only, open-world mutation, but the description adds substantial context beyond them: changes apply immediately, all members receive a group update, removals and bans are not automatically undone, admin rights are typically required, and 'reset' invalidates the old link. This is exactly the extra behavioral detail the annotations cannot convey.
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?
Purpose and required-parameter reminder are front-loaded, and for 18 parameters nearly every clause carries needed meaning. It is delivered as one dense run-on paragraph, which slightly hurts scannability, but there is very little filler to cut.
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 18 parameters and no output schema, the description covers semantics for every notable field, side effects, permission requirements, and even the return shape ('Returns status and group_id'). An agent has everything needed to call it 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?
With 100% schema coverage, the baseline is 3, but the description genuinely elaborates on the schema: it explains each link_mode value, translates permission_send_messages 'only-admins' into 'announcement group,' clarifies that expiration_seconds 0 disables the timer, and stresses that member_label applies ONLY to the caller's own label. These interpretations go beyond the bare property descriptions.
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?
States a specific verb and resource ('Change an existing group's details, membership, admins, invite link, permissions or timer') and immediately scopes it with 'only the fields you pass change.' This clearly separates it from create_group, leave_group, and terminate_group without needing to open any schema.
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 routes to siblings: 'Use send_group_message to post, leave_group to exit,' and notes group_id comes from list_groups. It also prescribes prerequisites ('Admin rights are needed for most changes'). It does not, however, distinguish itself from terminate_group or compare against create_group, so it stops short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_profileAIdempotent
Change your own Signal profile, which is uploaded to Signal's servers and seen by people you share your profile with. Only the fields you pass change. name: display name (alias of given_name; given_name wins if both are set). given_name / family_name: the two parts of your profile name. about: bio text; about_emoji: emoji shown next to it. mobilecoin_address: base64-encoded MobileCoin public address. avatar_path: local image file (JPEG or PNG) inside the allowed send folders (SIGNAL_MCP_SEND_ROOTS), no hidden paths. remove_avatar (default false): clear the current photo. Returns status 'profile updated'. To label someone else locally use update_contact; to rename a linked device use update_device; for account settings use update_account.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Display (given) name to set; alias of given_name | |
| about | No | About/bio text | |
| given_name | No | Profile given name | |
| about_emoji | No | Emoji shown next to the about text | |
| avatar_path | No | Local JPEG/PNG path inside the allowed send folders (SIGNAL_MCP_SEND_ROOTS) | |
| family_name | No | Profile family name | |
| remove_avatar | No | Remove current avatar | |
| mobilecoin_address | No | MobileCoin address (base64) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations already declaring readOnly=false, destructive=false, idempotent=true and openWorld=true, the description still adds material context: profile data is 'uploaded to Signal's servers and seen by people you share your profile with' (privacy exposure), 'Only the fields you pass change' (partial-update semantics), the return string, and avatar path constraints. It does not detail failure modes for invalid paths, so it stops short of 5.
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?
Purpose and sibling routing are front-loaded, and there is little waste. However, the parameter walkthrough is delivered as a single dense run-on block rather than being broken out, which slightly hurts scannability for an 8-parameter tool.
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?
For a no-required-parameter mutation tool with no output schema, the definition covers visibility of the change, partial-update behavior, removal semantics, path restrictions, and the return value. An agent has everything needed to invoke it 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 coverage is already 100%, but the description adds real meaning beyond it: the name/given_name alias with the precedence rule ('given_name wins if both are set'), remove_avatar's default, and the allowed-roots restriction on avatar_path. That precedence rule in particular is not derivable from 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?
States a specific verb and resource ('Change your own Signal profile') and immediately scopes it to the caller's own profile versus others. It explicitly names the sibling tools it is not (update_contact, update_device, update_account), so an agent can route correctly without opening any schema.
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?
Offers explicit alternatives with the condition that selects each: 'To label someone else locally use update_contact; to rename a linked device use update_device; for account settings use update_account.' Nothing is left to inference about when to pick this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upload_sticker_packA
Publish a new sticker pack made from your own images to Signal's servers and get a shareable signal.art link. path (required): local path to a manifest.json (with the sticker images next to it) or to a zip containing the manifest and images. The file must be inside an allowed folder (~/Downloads/signal-attachments, ~/Downloads, ~/Desktop, ~/Documents, or the SIGNAL_MCP_SEND_ROOTS list) and not in a hidden folder. The pack is public to anyone with the link and cannot be deleted through this tool. Invalid packs or oversized images return an error. Returns {url}. Use add_sticker_pack to install an existing pack.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Local path to manifest.json or a zip containing the sticker pack |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, openWorldHint=true, destructiveHint=false), but the description adds what annotations cannot: the pack becomes public to anyone with the link, it cannot be deleted through this tool, invalid or oversized images error out, and the return is {url}. These are consequential, non-obvious behaviors for an irreversible publish action.
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?
Front-loaded with the purpose, then path rules, side effects, error behavior, and the sibling pointer — every sentence carries weight. It is a dense single paragraph rather than scannable structure, which slightly hurts fast parsing, but there is no filler.
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?
With no output schema, the description supplies the return shape ({url}) and the failure mode (error on invalid/oversized packs). Combined with the visibility and deletion constraints, an agent has everything needed to invoke this correctly and warn the user about permanence.
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 coverage is 100% for the single path parameter, so the baseline would be 3, but the description materially enriches it: the value may point to a manifest.json (with images beside it) or a zip, and must sit inside an enumerated allowlist of folders while avoiding hidden folders. That is real semantics beyond the schema's one-line type description.
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?
States a specific verb and resource ('Publish a new sticker pack... to Signal's servers') plus the concrete outcome (shareable signal.art link). It explicitly distinguishes itself from add_sticker_pack, which installs existing packs rather than publishing new ones, so an agent can route without opening either schema.
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?
Gives both the positive trigger (publishing your own images as a new pack) and the alternative with its condition ('Use add_sticker_pack to install an existing pack'). The allowed-folder constraint and the hidden-folder exclusion further define when a call will be valid.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
vote_pollAIdempotent
Cast or change your vote on an open Signal poll in a DM or group; the vote is visible to participants. Use create_poll to start a poll, terminate_poll to close your own. A poll has no separate id: identify it by target_author (E.164 number of the poll's creator) + target_timestamp (ms timestamp of the poll message, from create_poll or get_conversation). votes: 0-based indices into the poll's options — exactly one for a single-choice poll, all chosen indices at once for multi-select (each call replaces your previous vote). Give recipient (E.164) for a DM poll or group_id for a group poll; neither is an error. Voting on a terminated poll fails. Contacts Signal's servers; a local per-poll counter is incremented so re-votes supersede earlier ones. Returns {status: 'vote sent'}.
| Name | Required | Description | Default |
|---|---|---|---|
| votes | Yes | Option indices to vote for (0-based). Single item for single-choice polls. | |
| group_id | No | Group ID for a group poll — provide this OR recipient | |
| recipient | No | Phone number for a DM poll — provide this OR group_id | |
| target_author | Yes | Phone number of the poll creator (E.164) | |
| target_timestamp | Yes | Timestamp of the poll message (from get_conversation) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=true, openWorldHint=true). Description adds substantial context: vote visibility to participants, replacement semantics for re-votes, server contact, local per-poll counter, and return value. Aligns with annotations (idempotentHint matches re-vote superseding).
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?
Front-loaded with purpose and alternatives, but dense with multiple clauses in later sentences. Every sentence earns its place, though the description could be slightly trimmed without losing critical information.
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?
No output schema exists, but the description provides the return value. Covers identification, parameter usage, failure conditions, and server interaction. Complete for a voting tool of this complexity.
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 100%, so baseline is 3. However, the description adds meaning beyond schema: identification via target_author + target_timestamp, votes semantics (0-based indices, single-choice vs multi-select, each call replaces previous vote), and DM vs group parameter selection. This significantly enriches parameter understanding.
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?
States a specific verb+resource: 'Cast or change your vote on an open Signal poll in a DM or group.' Clearly distinguishes from siblings create_poll and terminate_poll, which are named as alternatives.
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 names create_poll and terminate_poll as alternative tools and their use cases. Also details how to identify the poll, which parameters to provide for DM vs group, and the failure condition (voting on a terminated poll fails).
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.
13 tool updates
v1.43.0- Changed
add_device1 field changed- changed
Input schema / properties / uri / descriptionPrevious value: -"Device link URI (from signal-cli link output)"New value: +"Device link URI (sgnl://linkdevice?...) from the new device's QR code or signal-cli link output"
- Changed
find_contact1 field changed- changed
Input schema / properties / query / descriptionPrevious value: -"Name or phone number fragment to search for"New value: +"Case-insensitive fragment of a name, nickname, username or phone number"
- Changed
get_conversation3 fields changed- changed
Input schema / properties / limit / descriptionPrevious value: -"Max messages to return (default: 50)"New value: +"Max messages to return (default 50, clamped 1-500)" - changed
Input schema / properties / offset / descriptionPrevious value: -"Number of messages to skip for pagination (default: 0)"New value: +"Number of newest messages to skip for pagination (default: 0)" - changed
Input schema / properties / recipient / descriptionPrevious value: -"Phone number or group ID"New value: +"E.164 phone number for a DM, or group ID (from list_groups)"
- Changed
list_identities1 field changed- changed
Input schema / properties / number / descriptionPrevious value: -"Filter to a specific contact (optional)"New value: +"Only this contact's keys (E.164 phone number); omit for all"
- Changed
mark_as_unread1 field changed- changed
Input schema / properties / message_ids / descriptionPrevious value: -"List of message IDs to mark as unread"New value: +"Message id strings as returned by get_conversation, get_unread or search_messages"
- Changed
search_messages1 field changed- changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum results to return (default 50)"New value: +"Maximum results to return (default 50, clamped 1-500)"
- Changed
send_message1 field changed- added
Input schema / properties / formattingAdded value: +{ + "description": "Convert **bold**, *italic*, ~~strikethrough~~, `monospace`, ||spoiler|| to Signal text formatting. Default false.", + "type": "boolean" +}
- Changed
send_message_request_response2 fields changed- changed
Input schema / properties / accept / descriptionPrevious value: -"true to accept and start chatting, false to decline/block"New value: +"true to accept (shares your profile), false to decline (does not block)" - changed
Input schema / properties / sender / descriptionPrevious value: -"Phone number of the contact who sent the message request"New value: +"Phone number (E.164) of the contact who sent the message request"
- Changed
send_read_receipt1 field changed- changed
Input schema / properties / timestamps / descriptionPrevious value: -"Timestamps of the messages to mark as read (from get_conversation sent_at/received_at fields)"New value: +"Millisecond timestamps of the messages to acknowledge (the message id in get_conversation)"
- Changed
set_expiration_timer2 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID for a group conversation"New value: +"Group ID (from list_groups) for a group conversation; wins if recipient is also given" - changed
Input schema / properties / recipient / descriptionPrevious value: -"Phone number for a direct conversation"New value: +"Phone number (E.164) for a direct conversation"
- Changed
trust_identity2 fields changed- changed
Input schema / properties / number / descriptionPrevious value: -"Phone number to trust"New value: +"Phone number (E.164) whose identity key to trust" - changed
Input schema / properties / safety_number / descriptionPrevious value: -"Verified safety number (leave blank to trust all known keys)"New value: +"Safety number or fingerprint you verified (from list_identities); omit to trust all known keys unverified"
- Changed
update_group8 fields changed- changed
Input schema / properties / add_admins / descriptionPrevious value: -"Phone numbers to promote to admin"New value: +"Phone numbers (E.164) to promote to admin" - changed
Input schema / properties / add_members / descriptionPrevious value: -"Phone numbers to add"New value: +"Phone numbers (E.164) to add" - changed
Input schema / properties / avatar / descriptionPrevious value: -"Local image file path for the new group avatar"New value: +"Local image file path for the new group avatar (must be inside the allowed send folders)" - changed
Input schema / properties / ban_members / descriptionPrevious value: -"Members to ban from (re)joining the group"New value: +"Phone numbers (E.164) to ban from (re)joining the group" - changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID to update"New value: +"Group ID to update (get from list_groups)" - changed
Input schema / properties / remove_admins / descriptionPrevious value: -"Phone numbers to demote from admin"New value: +"Phone numbers (E.164) to demote from admin" - changed
Input schema / properties / remove_members / descriptionPrevious value: -"Phone numbers to remove"New value: +"Phone numbers (E.164) to remove" - changed
Input schema / properties / unban_members / descriptionPrevious value: -"Members to remove from the ban list"New value: +"Phone numbers (E.164) to remove from the ban list"
- Changed
update_profile1 field changed- changed
Input schema / properties / avatar_path / descriptionPrevious value: -"Path to avatar image file"New value: +"Local JPEG/PNG path inside the allowed send folders (SIGNAL_MCP_SEND_ROOTS)"
2 tool updates
v1.42.0- Changed
send_group_message1 field changed- added
Input schema / properties / formattingAdded value: +{ + "description": "Convert **bold**, *italic*, ~~strikethrough~~, `monospace`, ||spoiler|| to Signal text formatting. Default false.", + "type": "boolean" +}
- Changed
send_note_to_self1 field changed- changed
Input schema / properties / message / descriptionPrevious value: -"Note text to save. Supports **bold**, ~~strikethrough~~, `monospace`"New value: +"Note text to save. Supports **bold**, *italic*, ~~strikethrough~~, `monospace`, ||spoiler||"
21 tool updates
v1.40.1- Changed
create_group1 field changed- added
Input schema / properties / avatarAdded value: +{ + "description": "Optional local image file path for the group avatar", + "type": "string" +}
- Changed
find_contact1 field changed- added
Input schema / properties / all_recipientsAdded value: +{ + "default": false, + "description": "Also include recipients that are not in your address book (e.g. members of your groups), with their profile names", + "type": "boolean" +}
- Changed
get_attachment1 field changed- changed
Input schema / properties / filename / descriptionPrevious value: -"Attachment filename (get from list_attachments)"New value: +"Attachment filename (from list_attachments) or signal-cli attachment id"
- Changed
get_user_status2 fields changed- added
Input schema / properties / usernamesAdded value: +{ + "description": "List of Signal usernames or username links to check", + "items": { + "type": "string" + }, + "type": "array" +} - removed
Input schema / requiredRemoved value: -[ - "recipients" -]
- Changed
leave_group2 fields changed- added
Input schema / properties / adminsAdded value: +{ + "description": "Members to make admin before leaving — required if you are the only admin", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / deleteAdded value: +{ + "description": "Also delete all local group data after leaving", + "type": "boolean" +}
- Changed
list_contacts2 fields changed- added
Input schema / properties / all_recipientsAdded value: +{ + "default": false, + "description": "Also include recipients that are not in your address book (e.g. members of your groups), with their profile names", + "type": "boolean" +} - added
Input schema / properties / blockedAdded value: +{ + "description": "true = only blocked contacts, false = only unblocked (omit for all)", + "type": "boolean" +}
- Changed
list_groups1 field changed- added
Input schema / properties / group_idAdded value: +{ + "description": "Optional: return only this group", + "type": "string" +}
- Changed
receive_direct5 fields changed- added
Input schema / properties / ignore_attachmentsAdded value: +{ + "default": false, + "description": "Don't download attachments", + "type": "boolean" +} - added
Input schema / properties / ignore_avatarsAdded value: +{ + "default": false, + "description": "Don't download avatars", + "type": "boolean" +} - added
Input schema / properties / ignore_stickersAdded value: +{ + "default": false, + "description": "Don't download sticker packs", + "type": "boolean" +} - added
Input schema / properties / ignore_storiesAdded value: +{ + "default": false, + "description": "Don't receive story messages", + "type": "boolean" +} - added
Input schema / properties / max_messagesAdded value: +{ + "description": "Return after this many messages (default: no limit)", + "type": "integer" +}
- Changed
receive_messages1 field changed- added
Input schema / properties / max_messagesAdded value: +{ + "description": "Return after this many messages (default: no limit)", + "type": "integer" +}
- Changed
remove_contact2 fields changed- added
Input schema / properties / forgetAdded value: +{ + "default": false, + "description": "Delete all data for this recipient, including identity keys and sessions", + "type": "boolean" +} - added
Input schema / properties / hideAdded value: +{ + "default": false, + "description": "Hide the contact but keep its data", + "type": "boolean" +}
- Changed
send_attachment11 fields changed- added
Input schema / properties / no_urgentAdded value: +{ + "default": false, + "description": "Send without the urgent flag, so the recipient gets no push notification", + "type": "boolean" +} - added
Input schema / properties / notify_selfAdded value: +{ + "default": false, + "description": "If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message", + "type": "boolean" +} - added
Input schema / properties / quote_attachmentsAdded value: +{ + "description": "Attachments of the quoted message as 'contentType[:filename[:previewFile]]', e.g. 'image/png:photo.png'", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / quote_authorAdded value: +{ + "description": "Phone number (E.164) of the author of the message being quoted/replied to", + "type": "string" +} - added
Input schema / properties / quote_mentionsAdded value: +{ + "description": "@mentions inside the quoted text, same shape as mentions: {start, length, author}", + "items": { + "properties": { + "author": { + "type": "string" + }, + "length": { + "type": "integer" + }, + "start": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / quote_messageAdded value: +{ + "description": "Text of the quoted message shown in the quote bubble. Default: looked up in the local store by quote_author + quote_timestamp", + "type": "string" +} - added
Input schema / properties / quote_text_stylesAdded value: +{ + "description": "Styles inside the quoted text as 'start:length:STYLE' (BOLD, ITALIC, SPOILER, STRIKETHROUGH, MONOSPACE)", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / quote_timestampAdded value: +{ + "description": "Timestamp of the message being quoted/replied to (from get_conversation)", + "type": "integer" +} - added
Input schema / properties / usernameAdded value: +{ + "description": "Signal username (e.g. alice.42) or username link, instead of recipient", + "type": "string" +} - added
Input schema / properties / voice_noteAdded value: +{ + "default": false, + "description": "Mark audio attachments as voice notes (played inline in Signal)", + "type": "boolean" +} - removed
Input schema / requiredRemoved value: -[ - "recipient" -]
- Changed
send_group_attachment9 fields changed- added
Input schema / properties / no_urgentAdded value: +{ + "default": false, + "description": "Send without the urgent flag, so the recipient gets no push notification", + "type": "boolean" +} - added
Input schema / properties / notify_selfAdded value: +{ + "default": false, + "description": "If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message", + "type": "boolean" +} - added
Input schema / properties / quote_attachmentsAdded value: +{ + "description": "Attachments of the quoted message as 'contentType[:filename[:previewFile]]', e.g. 'image/png:photo.png'", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / quote_authorAdded value: +{ + "description": "Phone number (E.164) of the author of the message being quoted/replied to", + "type": "string" +} - added
Input schema / properties / quote_mentionsAdded value: +{ + "description": "@mentions inside the quoted text, same shape as mentions: {start, length, author}", + "items": { + "properties": { + "author": { + "type": "string" + }, + "length": { + "type": "integer" + }, + "start": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / quote_messageAdded value: +{ + "description": "Text of the quoted message shown in the quote bubble. Default: looked up in the local store by quote_author + quote_timestamp", + "type": "string" +} - added
Input schema / properties / quote_text_stylesAdded value: +{ + "description": "Styles inside the quoted text as 'start:length:STYLE' (BOLD, ITALIC, SPOILER, STRIKETHROUGH, MONOSPACE)", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / quote_timestampAdded value: +{ + "description": "Timestamp of the message being quoted/replied to (from get_conversation)", + "type": "integer" +} - added
Input schema / properties / voice_noteAdded value: +{ + "default": false, + "description": "Mark audio attachments as voice notes (played inline in Signal)", + "type": "boolean" +}
- Changed
send_group_message14 fields changed- added
Input schema / properties / no_urgentAdded value: +{ + "default": false, + "description": "Send without the urgent flag, so the recipient gets no push notification", + "type": "boolean" +} - added
Input schema / properties / notify_selfAdded value: +{ + "default": false, + "description": "If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message", + "type": "boolean" +} - added
Input schema / properties / preview_descriptionAdded value: +{ + "description": "Link preview description", + "type": "string" +} - added
Input schema / properties / preview_imageAdded value: +{ + "description": "Local image file for the link preview thumbnail", + "type": "string" +} - added
Input schema / properties / preview_titleAdded value: +{ + "description": "Link preview title (needed for the card to render)", + "type": "string" +} - added
Input schema / properties / preview_urlAdded value: +{ + "description": "URL for a link preview card; the same URL must also appear in the message text", + "type": "string" +} - added
Input schema / properties / quote_attachmentsAdded value: +{ + "description": "Attachments of the quoted message as 'contentType[:filename[:previewFile]]', e.g. 'image/png:photo.png'", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / quote_author / descriptionPrevious value: -"Phone number (E.164) of the author of the message being quoted"New value: +"Phone number (E.164) of the author of the message being quoted/replied to" - added
Input schema / properties / quote_mentionsAdded value: +{ + "description": "@mentions inside the quoted text, same shape as mentions: {start, length, author}", + "items": { + "properties": { + "author": { + "type": "string" + }, + "length": { + "type": "integer" + }, + "start": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / quote_messageAdded value: +{ + "description": "Text of the quoted message shown in the quote bubble. Default: looked up in the local store by quote_author + quote_timestamp", + "type": "string" +} - added
Input schema / properties / quote_text_stylesAdded value: +{ + "description": "Styles inside the quoted text as 'start:length:STYLE' (BOLD, ITALIC, SPOILER, STRIKETHROUGH, MONOSPACE)", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / quote_timestamp / descriptionPrevious value: -"Timestamp of the quoted message (from get_conversation)"New value: +"Timestamp of the message being quoted/replied to (from get_conversation)" - added
Input schema / properties / story_authorAdded value: +{ + "description": "Phone number of the story's author, to reply to a story", + "type": "string" +} - added
Input schema / properties / story_timestampAdded value: +{ + "description": "Timestamp of the story being replied to", + "type": "integer" +}
- Changed
send_message16 fields changed- added
Input schema / properties / end_sessionAdded value: +{ + "default": false, + "description": "Reset the session with this contact instead of sending a message", + "type": "boolean" +} - added
Input schema / properties / no_urgentAdded value: +{ + "default": false, + "description": "Send without the urgent flag, so the recipient gets no push notification", + "type": "boolean" +} - added
Input schema / properties / notify_selfAdded value: +{ + "default": false, + "description": "If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message", + "type": "boolean" +} - added
Input schema / properties / preview_descriptionAdded value: +{ + "description": "Link preview description", + "type": "string" +} - added
Input schema / properties / preview_imageAdded value: +{ + "description": "Local image file for the link preview thumbnail", + "type": "string" +} - added
Input schema / properties / preview_titleAdded value: +{ + "description": "Link preview title (needed for the card to render)", + "type": "string" +} - added
Input schema / properties / preview_urlAdded value: +{ + "description": "URL for a link preview card; the same URL must also appear in the message text", + "type": "string" +} - added
Input schema / properties / quote_attachmentsAdded value: +{ + "description": "Attachments of the quoted message as 'contentType[:filename[:previewFile]]', e.g. 'image/png:photo.png'", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / quote_author / descriptionPrevious value: -"Phone number of the author of the message being quoted/replied to"New value: +"Phone number (E.164) of the author of the message being quoted/replied to" - added
Input schema / properties / quote_mentionsAdded value: +{ + "description": "@mentions inside the quoted text, same shape as mentions: {start, length, author}", + "items": { + "properties": { + "author": { + "type": "string" + }, + "length": { + "type": "integer" + }, + "start": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / quote_messageAdded value: +{ + "description": "Text of the quoted message shown in the quote bubble. Default: looked up in the local store by quote_author + quote_timestamp", + "type": "string" +} - added
Input schema / properties / quote_text_stylesAdded value: +{ + "description": "Styles inside the quoted text as 'start:length:STYLE' (BOLD, ITALIC, SPOILER, STRIKETHROUGH, MONOSPACE)", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / story_authorAdded value: +{ + "description": "Phone number of the story's author, to reply to a story", + "type": "string" +} - added
Input schema / properties / story_timestampAdded value: +{ + "description": "Timestamp of the story being replied to", + "type": "integer" +} - added
Input schema / properties / usernameAdded value: +{ + "description": "Signal username (e.g. alice.42) or username link, instead of recipient", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "recipient", - "message" -]New value: +[ + "message" +]
- Changed
send_note_to_self7 fields changed- added
Input schema / properties / no_urgentAdded value: +{ + "default": false, + "description": "Send without the urgent flag, so the recipient gets no push notification", + "type": "boolean" +} - added
Input schema / properties / notify_selfAdded value: +{ + "default": false, + "description": "If you are among the recipients, deliver as a normal (notifying) message instead of a silent sync message", + "type": "boolean" +} - added
Input schema / properties / preview_descriptionAdded value: +{ + "description": "Link preview description", + "type": "string" +} - added
Input schema / properties / preview_imageAdded value: +{ + "description": "Local image file for the link preview thumbnail", + "type": "string" +} - added
Input schema / properties / preview_titleAdded value: +{ + "description": "Link preview title (needed for the card to render)", + "type": "string" +} - added
Input schema / properties / preview_urlAdded value: +{ + "description": "URL for a link preview card; the same URL must also appear in the message text", + "type": "string" +} - added
Input schema / properties / voice_noteAdded value: +{ + "default": false, + "description": "Mark audio attachments as voice notes (played inline in Signal)", + "type": "boolean" +}
- Added
send_story - Changed
set_typing2 fields changed- added
Input schema / properties / group_idAdded value: +{ + "description": "Group ID (base64) to show typing in a group", + "type": "string" +} - removed
Input schema / requiredRemoved value: -[ - "recipient" -]
- Added
terminate_group - Changed
update_contact6 fields changed- added
Input schema / properties / family_nameAdded value: +{ + "description": "Contact family name", + "type": "string" +} - added
Input schema / properties / given_nameAdded value: +{ + "description": "Contact given name", + "type": "string" +} - added
Input schema / properties / nick_family_nameAdded value: +{ + "description": "Nickname family name", + "type": "string" +} - added
Input schema / properties / nick_given_nameAdded value: +{ + "description": "Nickname given name", + "type": "string" +} - added
Input schema / properties / noteAdded value: +{ + "description": "Private note about the contact", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "number", - "name" -]New value: +[ + "number" +]
- Changed
update_group9 fields changed- added
Input schema / properties / avatarAdded value: +{ + "description": "Local image file path for the new group avatar", + "type": "string" +} - added
Input schema / properties / ban_membersAdded value: +{ + "description": "Members to ban from (re)joining the group", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / member_labelAdded value: +{ + "description": "YOUR OWN member label in this group (not other members')", + "type": "string" +} - added
Input schema / properties / member_label_emojiAdded value: +{ + "description": "Emoji for YOUR OWN member label", + "type": "string" +} - added
Input schema / properties / permission_add_memberAdded value: +{ + "description": "Who may add new members", + "enum": [ + "every-member", + "only-admins" + ], + "type": "string" +} - added
Input schema / properties / permission_edit_detailsAdded value: +{ + "description": "Who may edit group name, description, avatar, timer", + "enum": [ + "every-member", + "only-admins" + ], + "type": "string" +} - added
Input schema / properties / permission_send_messagesAdded value: +{ + "description": "Who may send messages ('only-admins' = announcement group)", + "enum": [ + "every-member", + "only-admins" + ], + "type": "string" +} - added
Input schema / properties / reset_linkAdded value: +{ + "description": "Generate a new invite link, invalidating the old one", + "type": "boolean" +} - added
Input schema / properties / unban_membersAdded value: +{ + "description": "Members to remove from the ban list", + "items": { + "type": "string" + }, + "type": "array" +}
- Changed
update_profile5 fields changed- added
Input schema / properties / about_emojiAdded value: +{ + "description": "Emoji shown next to the about text", + "type": "string" +} - added
Input schema / properties / family_nameAdded value: +{ + "description": "Profile family name", + "type": "string" +} - added
Input schema / properties / given_nameAdded value: +{ + "description": "Profile given name", + "type": "string" +} - added
Input schema / properties / mobilecoin_addressAdded value: +{ + "description": "MobileCoin address (base64)", + "type": "string" +} - changed
Input schema / properties / name / descriptionPrevious value: -"Display name to set"New value: +"Display (given) name to set; alias of given_name"
1 tool update
v1.39.0- Changed
search_messages2 fields changed- added
Input schema / properties / sinceAdded value: +{ + "description": "Only messages at or after this ISO datetime (e.g. 2024-01-01 or 2024-01-01T09:00:00)", + "type": "string" +} - added
Input schema / properties / untilAdded value: +{ + "description": "Only messages strictly before this ISO datetime (exclusive; until=2024-01-02 includes all of Jan 1)", + "type": "string" +}
3 tool updates
v1.36.0- Changed
send_group_message1 field changed- changed
Input schema / properties / mentions / descriptionPrevious value: -"List of @mentions. Each item: {start: character offset of the mention in the message, length: character count of the mention, author: E.164 phone number of the mentioned member}. Example: message='Hello @Alice', mentions=[{start:6,length:6,author:'+1234567890'}]"New value: +"List of @mentions. Each item: {start: offset of the mention in the message (UTF-16 code units, not codepoints), length: mention length (UTF-16 code units), author: E.164 phone number of the mentioned member}. Example: message='Hello @Alice', mentions=[{start:6,length:6,author:'+1234567890'}]"
- Changed
terminate_poll2 fields changed- removed
Input schema / properties / poll_idRemoved value: -{ - "description": "Poll ID from the original poll message data", - "type": "integer" -} - changed
Input schema / requiredPrevious value: -[ - "target_author", - "target_timestamp", - "poll_id" -]New value: +[ + "target_author", + "target_timestamp" +]
- Changed
vote_poll2 fields changed- removed
Input schema / properties / poll_idRemoved value: -{ - "description": "Poll ID from the poll message data", - "type": "integer" -} - changed
Input schema / requiredPrevious value: -[ - "target_author", - "target_timestamp", - "poll_id", - "votes" -]New value: +[ + "target_author", + "target_timestamp", + "votes" +]
1 tool update
v1.35.0- Removed
get_configuration
1 tool update
v1.34.1- Changed
send_note_to_self4 fields changed- added
Input schema / properties / attachmentsAdded value: +{ + "description": "File paths to attach (e.g. a QR code or screenshot)", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / message / descriptionPrevious value: -"Note text to save"New value: +"Note text to save. Supports **bold**, ~~strikethrough~~, `monospace`" - added
Input schema / properties / quote_authorAdded value: +{ + "description": "Your own account number, to thread this note under a previous one", + "type": "string" +} - added
Input schema / properties / quote_timestampAdded value: +{ + "description": "Timestamp of the note being followed up on (from a prior send_note_to_self result)", + "type": "integer" +}
8 tool updates
v1.33.3- Added
cancel_scheduled_message - Added
find_contact - Added
get_webhook - Added
list_scheduled_messages - Added
receive_direct - Added
run_scheduled_messages - Added
schedule_message - Added
set_webhook
3 tool updates
v0.1.8- Changed
send_group_message7 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID (get from list_groups)"New value: +"Group ID (from list_groups)" - changed
Input schema / properties / mentions / descriptionPrevious value: -"List of @mentions: each item is {start, length, author} where start/length are character offsets into the message and author is a phone number"New value: +"List of @mentions. Each item: {start: character offset of the mention in the message, length: character count of the mention, author: E.164 phone number of the mentioned member}. Example: message='Hello @Alice', mentions=[{start:6,length:6,author:'+1234567890'}]" - added
Input schema / properties / mentions / items / properties / author / descriptionAdded value: +"E.164 phone number of the mentioned group member" - added
Input schema / properties / mentions / items / properties / length / descriptionAdded value: +"Length of the mention text in characters" - added
Input schema / properties / mentions / items / properties / start / descriptionAdded value: +"Character offset of the mention in the message text" - changed
Input schema / properties / quote_author / descriptionPrevious value: -"Phone number of the author of the message being quoted/replied to"New value: +"Phone number (E.164) of the author of the message being quoted" - changed
Input schema / properties / quote_timestamp / descriptionPrevious value: -"Timestamp of the message being quoted/replied to (from get_conversation)"New value: +"Timestamp of the quoted message (from get_conversation)"
- Changed
send_read_receipt2 fields changed- changed
Input schema / properties / sender / descriptionPrevious value: -"Phone number of the message sender"New value: +"Phone number (E.164) of the contact whose messages you are acknowledging" - changed
Input schema / properties / timestamps / descriptionPrevious value: -"List of message timestamps to mark read"New value: +"Timestamps of the messages to mark as read (from get_conversation sent_at/received_at fields)"
- Changed
set_pin1 field changed- changed
Input schema / properties / pin / descriptionPrevious value: -"4–20 digit PIN"New value: +"4–20 digit numeric PIN (e.g. '123456')"
23 tool updates
v0.1.2- Changed
admin_delete_message3 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID"New value: +"Group ID where the message was sent (get from list_groups)" - changed
Input schema / properties / target_author / descriptionPrevious value: -"Phone number of the message author"New value: +"Phone number of the user who sent the message" - changed
Input schema / properties / target_timestamp / descriptionPrevious value: -"Timestamp of the message to delete"New value: +"Timestamp of the message to delete (from get_conversation)"
- Changed
block_contact1 field changed- changed
Input schema / properties / number / descriptionPrevious value: -"Phone number to block"New value: +"Phone number to block (E.164 format, e.g. +1234567890)"
- Changed
create_group3 fields changed- changed
Input schema / properties / description / descriptionPrevious value: -"Optional group description"New value: +"Optional group description shown in group info" - changed
Input schema / properties / members / descriptionPrevious value: -"Phone numbers of initial members"New value: +"Phone numbers (E.164) of initial members to invite" - changed
Input schema / properties / name / descriptionPrevious value: -"Group name"New value: +"Group name visible to all members"
- Changed
create_poll5 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID for a group poll"New value: +"Group ID for a group poll — provide this OR recipient" - changed
Input schema / properties / multi_select / descriptionPrevious value: -"Allow multiple answer selection (default false)"New value: +"Allow voters to select multiple options (default: false = single choice only)" - changed
Input schema / properties / options / descriptionPrevious value: -"List of answer options (at least 2)"New value: +"List of answer options (minimum 2 required)" - changed
Input schema / properties / question / descriptionPrevious value: -"The poll question"New value: +"The poll question text" - changed
Input schema / properties / recipient / descriptionPrevious value: -"Phone number for a DM poll"New value: +"Phone number for a DM poll — provide this OR group_id"
- Changed
edit_message4 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID for a group message"New value: +"Group ID for a group message edit" - changed
Input schema / properties / message / descriptionPrevious value: -"New message text"New value: +"New message text to replace the original" - changed
Input schema / properties / recipient / descriptionPrevious value: -"Phone number for a DM message"New value: +"Phone number for a DM message edit" - changed
Input schema / properties / target_timestamp / descriptionPrevious value: -"Timestamp of the message to edit"New value: +"Timestamp of the message to edit (from get_conversation or send_message response)"
- Changed
join_group1 field changed- changed
Input schema / properties / uri / descriptionPrevious value: -"Group invite link (https://signal.group/#...)"New value: +"Group invite link starting with https://signal.group/#"
- Changed
leave_group1 field changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID to leave"New value: +"Group ID to leave (get from list_groups)"
- Changed
list_contacts1 field changed- changed
Input schema / properties / search / descriptionPrevious value: -"Filter contacts by name or number (case-insensitive substring)"New value: +"Filter contacts by name or number (case-insensitive substring match)"
- Changed
pin_message4 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID for group conversations"New value: +"Group ID for group conversations — provide this OR recipient" - changed
Input schema / properties / recipient / descriptionPrevious value: -"Phone number for DM conversations"New value: +"Phone number for DM conversations — provide this OR group_id" - changed
Input schema / properties / target_author / descriptionPrevious value: -"Phone number of the message author"New value: +"Phone number of the message author (E.164)" - changed
Input schema / properties / target_timestamp / descriptionPrevious value: -"Timestamp of the message to pin"New value: +"Timestamp of the message to pin (from get_conversation)"
- Changed
remove_contact1 field changed- changed
Input schema / properties / number / descriptionPrevious value: -"Phone number to remove"New value: +"Phone number to remove (E.164 format)"
- Changed
send_attachment3 fields changed- changed
Input schema / properties / caption / descriptionPrevious value: -"Optional caption text"New value: +"Optional caption text shown below the attachment" - changed
Input schema / properties / paths / descriptionPrevious value: -"Multiple file paths to send in one message"New value: +"Multiple file paths to send as one message" - changed
Input schema / properties / view_once / descriptionPrevious value: -"Send as view-once (disappears after viewing)"New value: +"Send as view-once media — recipient can only view it once before it disappears"
- Changed
send_group_attachment3 fields changed- changed
Input schema / properties / caption / descriptionPrevious value: -"Optional caption text"New value: +"Optional caption text shown below the attachment" - changed
Input schema / properties / paths / descriptionPrevious value: -"Multiple file paths to send in one message"New value: +"Multiple file paths to send as one message" - changed
Input schema / properties / view_once / descriptionPrevious value: -"Send as view-once (disappears after viewing)"New value: +"Send as view-once media — each recipient can only view it once"
- Changed
send_group_message3 fields changed- changed
Input schema / properties / mentions / descriptionPrevious value: -"List of @mentions: each item is {start, length, author} where author is a phone number"New value: +"List of @mentions: each item is {start, length, author} where start/length are character offsets into the message and author is a phone number" - changed
Input schema / properties / quote_author / descriptionPrevious value: -"Phone number of the message being quoted/replied to"New value: +"Phone number of the author of the message being quoted/replied to" - changed
Input schema / properties / quote_timestamp / descriptionPrevious value: -"Timestamp of the message being quoted/replied to"New value: +"Timestamp of the message being quoted/replied to (from get_conversation)"
- Changed
send_group_sticker3 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID"New value: +"Group ID (get from list_groups)" - changed
Input schema / properties / pack_id / descriptionPrevious value: -"Sticker pack ID (hex string)"New value: +"Sticker pack ID (hex string from list_sticker_packs)" - changed
Input schema / properties / sticker_id / descriptionPrevious value: -"Sticker ID within the pack"New value: +"Sticker ID within the pack (from list_sticker_packs)"
- Changed
send_message2 fields changed- changed
Input schema / properties / quote_author / descriptionPrevious value: -"Phone number of the message being quoted/replied to"New value: +"Phone number of the author of the message being quoted/replied to" - changed
Input schema / properties / quote_timestamp / descriptionPrevious value: -"Timestamp of the message being quoted/replied to"New value: +"Timestamp of the message being quoted/replied to (from get_conversation)"
- Changed
send_sticker2 fields changed- changed
Input schema / properties / pack_id / descriptionPrevious value: -"Sticker pack ID (hex string)"New value: +"Sticker pack ID (hex string from list_sticker_packs)" - changed
Input schema / properties / sticker_id / descriptionPrevious value: -"Sticker ID within the pack"New value: +"Sticker ID within the pack (from list_sticker_packs)"
- Changed
set_typing1 field changed- changed
Input schema / properties / stop / descriptionPrevious value: -"True to stop typing indicator (default: False)"New value: +"Set to true to cancel an active typing indicator (default: false = start typing)"
- Changed
terminate_poll5 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID for a group poll"New value: +"Group ID for a group poll — provide this OR recipient" - changed
Input schema / properties / poll_id / descriptionPrevious value: -"Poll ID from the original poll message"New value: +"Poll ID from the original poll message data" - changed
Input schema / properties / recipient / descriptionPrevious value: -"Phone number for a DM poll"New value: +"Phone number for a DM poll — provide this OR group_id" - changed
Input schema / properties / target_author / descriptionPrevious value: -"Phone number of the poll creator (your own number)"New value: +"Phone number of the poll creator — must be your own number" - changed
Input schema / properties / target_timestamp / descriptionPrevious value: -"Timestamp of the poll message"New value: +"Timestamp of the poll message (from get_conversation)"
- Changed
unblock_contact1 field changed- changed
Input schema / properties / number / descriptionPrevious value: -"Phone number to unblock"New value: +"Phone number to unblock (E.164 format)"
- Changed
unpin_message4 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID for group conversations"New value: +"Group ID for group conversations — provide this OR recipient" - changed
Input schema / properties / recipient / descriptionPrevious value: -"Phone number for DM conversations"New value: +"Phone number for DM conversations — provide this OR group_id" - changed
Input schema / properties / target_author / descriptionPrevious value: -"Phone number of the message author"New value: +"Phone number of the message author (E.164)" - changed
Input schema / properties / target_timestamp / descriptionPrevious value: -"Timestamp of the pinned message"New value: +"Timestamp of the pinned message (from get_conversation)"
- Changed
update_account6 fields changed- changed
Input schema / properties / delete_username / descriptionPrevious value: -"Delete the current username"New value: +"Delete your current Signal username" - changed
Input schema / properties / device_name / descriptionPrevious value: -"Name shown on linked-device list"New value: +"Name for this device shown in linked devices list" - changed
Input schema / properties / discoverable_by_number / descriptionPrevious value: -"Allow others to find you by phone number"New value: +"Allow others to find your account by phone number" - changed
Input schema / properties / number_sharing / descriptionPrevious value: -"Share your number when sending messages"New value: +"Share your phone number when sending messages" - changed
Input schema / properties / unrestricted_unidentified_sender / descriptionPrevious value: -"Allow sealed-sender from anyone"New value: +"Allow sealed-sender messages from anyone (not just contacts)" - changed
Input schema / properties / username / descriptionPrevious value: -"Set a Signal username (without @)"New value: +"Set a Signal username (without @) as an alias for your number"
- Changed
update_device2 fields changed- changed
Input schema / properties / device_id / descriptionPrevious value: -"Device ID from list_devices"New value: +"Device ID (get from list_devices)" - changed
Input schema / properties / name / descriptionPrevious value: -"New name for the device"New value: +"New display name for the device"
- Changed
vote_poll6 fields changed- changed
Input schema / properties / group_id / descriptionPrevious value: -"Group ID for a group poll"New value: +"Group ID for a group poll — provide this OR recipient" - changed
Input schema / properties / poll_id / descriptionPrevious value: -"Poll ID from the original poll message"New value: +"Poll ID from the poll message data" - changed
Input schema / properties / recipient / descriptionPrevious value: -"Phone number for a DM poll"New value: +"Phone number for a DM poll — provide this OR group_id" - changed
Input schema / properties / target_author / descriptionPrevious value: -"Phone number of the poll creator"New value: +"Phone number of the poll creator (E.164)" - changed
Input schema / properties / target_timestamp / descriptionPrevious value: -"Timestamp of the poll message"New value: +"Timestamp of the poll message (from get_conversation)" - changed
Input schema / properties / votes / descriptionPrevious value: -"List of option indices to vote for (0-based)"New value: +"Option indices to vote for (0-based). Single item for single-choice polls."
72 tool updates
v0.1.0- First observed
add_device - First observed
add_sticker_pack - First observed
admin_delete_message - First observed
block_contact - First observed
clear_local_store - First observed
create_group - First observed
create_poll - First observed
delete_group_message - First observed
delete_local_messages - First observed
delete_message - First observed
edit_message - First observed
export_messages - First observed
finish_change_number - First observed
get_attachment - First observed
get_avatar - First observed
get_configuration - First observed
get_conversation - First observed
get_own_number - First observed
get_profile - First observed
get_sticker - First observed
get_unread - First observed
get_user_status - First observed
import_desktop - First observed
join_group - First observed
leave_group - First observed
list_accounts - First observed
list_attachments - First observed
list_contacts - First observed
list_conversations - First observed
list_devices - First observed
list_groups - First observed
list_identities - First observed
list_sticker_packs - First observed
mark_as_unread - First observed
pin_message - First observed
prune_store - First observed
react_to_message - First observed
receive_messages - First observed
remove_contact - First observed
remove_device - First observed
remove_pin - First observed
search_messages - First observed
send_attachment - First observed
send_contacts_sync - First observed
send_group_attachment - First observed
send_group_message - First observed
send_group_sticker - First observed
send_message - First observed
send_message_request_response - First observed
send_note_to_self - First observed
send_read_receipt - First observed
send_sticker - First observed
send_sync_request - First observed
set_expiration_timer - First observed
set_pin - First observed
set_typing - First observed
start_change_number - First observed
store_stats - First observed
submit_rate_limit_challenge - First observed
sync_desktop - First observed
terminate_poll - First observed
trust_identity - First observed
unblock_contact - First observed
unpin_message - First observed
update_account - First observed
update_configuration - First observed
update_contact - First observed
update_device - First observed
update_group - First observed
update_profile - First observed
upload_sticker_pack - First observed
vote_poll
TDQS
Scored across 81 tools
Despite 81 tools, descriptions carefully carve out boundaries (e.g. send_message vs send_group_message vs send_attachment vs send_note_to_self, and the many DM/group pairs like delete_message vs delete_group_message). A few near-duplicates exist (get_unread vs receive_messages vs receive_direct; get_profile vs find_contact vs get_user_status) but cross-references make the intent clear.
Strong verb_noun snake_case throughout (send_message, list_contacts, update_group, remove_device, set_typing). Minor deviations like send_message_request_response and the receive_* family are still readable and consistently styled.
81 tools is far beyond what an agent can navigate comfortably; many are thin variants (send_sticker vs send_group_sticker, delete_message vs delete_group_message, multiple receive_* and store-cleanup tools). This is an extreme surface for a single messaging server.
Coverage is exhaustive: messaging, groups, contacts, devices, stickers, polls, stories, reactions, pins, scheduling, identity/trust, account settings, webhooks, and local store management. CRUD and lifecycle operations are present across almost every domain.
Maintenance
Related MCP Connectors
Your own WhatsApp as an MCP server: read, search and send from any MCP client.
The official Planning Center MCP server for interacting with your ministry's data.
The official MCP Server for the Mux API
MCP server for OnceAsk, the AI-native current-address layer for people and agents.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceMCP Server for retrieving Signal messages using signal-export logic.8-
- AlicenseAqualityBmaintenanceLocal Signal MCP server: read via Signal Desktop, send via signal-cli9MIT
- FlicenseNot gradedqualityCmaintenanceMCP server for Signal via signal-cli that enables sending and receiving messages, managing contacts and groups, and reacting over stdio.8 npm-
- AlicenseNot gradedqualityAmaintenanceMCP server for a local-first messaging workspace that integrates Google Messages, WhatsApp, and Signal. It enables reading, sending, searching messages, and managing conversations through MCP tools.63-