phone-sms
Reads and sends SMS through a paired Android phone running the KDE Connect app, exposing tools to list conversations (newest first, filterable by contact or unread), read the last n messages of a thread, look up contacts by name or number fragment, and send individual or group texts to one or more numbers.
Talks to the KDE Connect daemon (kdeconnectd) over D-Bus on the local network, using the org.kde.kdeconnect.device.conversations interface to discover devices, load conversations, and hand outgoing SMS requests to the phone (e.g. sendWithoutConversation), with support for pinning a specific device by id.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@phone-smslist my unread text conversations"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
phone-sms
Site: https://phone-sms.vercel.app · Repo: https://github.com/h-3303/phone-sms
An MCP server that lets Claude (or any MCP client) read and send SMS through your own Android phone, from your own number. It talks to the phone over KDE Connect on your local network: no cloud relay, no SMS gateway account, no app to install beyond KDE Connect itself.
agent ──MCP──▶ phone-sms ──D-Bus──▶ kdeconnectd ──LAN──▶ KDE Connect (Android) ──▶ SMSTools:
Tool | Does |
| conversations, newest first, with the latest message; filter by contact or unread |
| the last n messages of one conversation |
| look up a contact by name or number fragment (from the phone's synced contacts) |
| send a text, or a group text to several numbers |
send_sms carries MCP's destructiveHint, and the server tells the model never to send until you
have approved the exact recipient and text in the conversation. Message contents never leave your
machine except as the model's context.
Requirements
Linux with a D-Bus session bus and KDE Connect (
kdeconnectd, a current release; packagekdeconnect). It does not need the Plasma desktop; it runs fine under GNOME, Hyprland, Sway…An Android phone with the KDE Connect app (F-Droid / Play), paired with the computer. On the phone, enable the SMS plugin (and Contacts if you want names) and grant the SMS and contacts permissions it asks for.
uv and Python 3.12+.
Check the pairing: kdeconnect-cli -l should list your phone as paired and reachable.
Related MCP server: mac-messages-mcp
Install
Claude Code, as a plugin (one step):
/plugin marketplace add h-3303/phone-sms
/plugin install phone-sms@phone-smsClaude Code, as a plain MCP server:
claude mcp add --scope user phone-sms -- uvx phone-smsAny other MCP client (Claude Desktop config shape, Cursor, Zed, …):
{
"mcpServers": {
"phone-sms": {
"command": "uvx",
"args": ["phone-sms"]
}
}
}From a checkout: uv run --directory /path/to/phone-sms -q phone-sms.
The server uses the first paired, reachable device. With several phones, pin one with
PHONE_SMS_DEVICE=<id> (the id kdeconnect-cli -l prints).
CLI
The same code paths, for checking things by hand:
phone-sms threads [-n 20] [--unread]
phone-sms read <thread_id> [-n 20]
phone-sms contact <name>
phone-sms send <number>... -m "text"
phone-sms # MCP server on stdioHow sending works
find_contact <name>gives the number;send_smstakes numbers, ideally in E.164 (+14375551234).The model shows you recipient and text and waits for your yes.
send_smsanswers handed to phone… oncekdeconnectdhas accepted the request. That is not delivery: the sent message shows up inlist_threads/read_threadonce the phone syncs it, usually within a minute.
Troubleshooting
"no paired, reachable device": open KDE Connect on the phone, same Wi-Fi,
kdeconnect-cli -l.Sent, but nothing arrives: on the phone, check that the SMS plugin is enabled for this computer and that Android granted KDE Connect the SMS permission. Watch the request leave the server with
dbus-monitor --session "interface='org.kde.kdeconnect.device.conversations',member='sendWithoutConversation'".Names missing: enable the Contacts plugin on both ends; vCards land in
~/.local/share/kpeoplevcard/kdeconnect-<device>/.The
kdeconnectdjournal line Unimplemented conversation of type 'r' comes from the notification-forwarding plugin, not SMS.
Notes for hackers
It uses org.kde.kdeconnect.device.conversations, the interface the kdeconnect-sms app uses.
The daemon object's introspection XML has duplicate methods, so device discovery is a raw D-Bus
call. requestConversation first emits only cached messages, so read_thread waits for count
messages or conversationLoaded, not for a quiet gap.
License
GPL-3.0-or-later, like KDE Connect.
Available Tools
4 toolsfind_contactBRead-only
Look up phone contacts by name or number fragment.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already declares this is a safe read, so the description doesn't need to reassure about mutation. It adds the useful detail that matching can be by name OR number fragment, but says nothing about auth needs, matching behavior, or result limits.
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 front-loaded sentence with zero filler. Every word 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?
An output schema exists, so return values need not be explained, and this is a simple single-parameter read. The remaining gap is the lack of any guidance on matching behavior or when to prefer this over the messaging siblings.
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 0%, so the schema alone gives no meaning for 'query'. The description partially compensates by explaining the query accepts a name or number fragment, but omits details like partial-match semantics or format expectations.
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 (look up) and resource (phone contacts) plus the matching method (name or number fragment). It naturally distinguishes itself from the messaging-oriented siblings (list_threads, read_thread, send_sms), though it never explicitly names or contrasts them.
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?
There is no explicit when-to-use guidance, no discussion of alternatives, and no exclusions. The purpose implies lookup usage, but an agent gets no routing help for choosing this over the sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_threadsARead-only
List SMS conversations, newest first, with the latest message of each.
Each line starts with the thread id, which read_thread takes.
contact: optional name or number fragment to filter on.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| contact | No | ||
| unread_only | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint already declares this is a safe read. The description goes beyond that by disclosing result ordering (newest first), that each thread carries its latest message, and the per-line output shape beginning with the thread id. It does not mention pagination or result caps, but with an output schema present the return shape is already partly covered.
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 lines, zero filler, and front-loaded with the core purpose and ordering before the read_thread linkage and the single parameter note. Every sentence 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?
With an output schema present the description need not explain return values, and it covers ordering, per-line format, and the read_thread connection. The main gap is the undocumented limit and unread_only parameters, which is a minor omission for an otherwise simple read-only listing tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the burden, yet it only documents one of three parameters: 'contact: optional name or number fragment to filter on.', which usefully clarifies the fragment-matching semantics. limit and unread_only are left entirely to their self-explanatory names and defaults, so compensation is partial.
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 SMS conversations') and adds distinguishing scope: newest-first ordering and inclusion of the latest message per thread. It also names the sibling read_thread and explains the linkage (thread id), so an agent can separate this listing tool from the read-one tool 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?
Usage is implied through the read_thread linkage ('Each line starts with the thread id, which read_thread takes'), which does suggest a list-then-read workflow. However, there is no explicit when-to-use vs when-not, no mention of find_contact or send_sms, and no stated prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_threadBRead-only
Read the most recent count messages of one conversation, oldest first.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | ||
| thread_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already establishes the safe-read profile, so the bar is lower. The description usefully adds ordering semantics ('oldest first') and the recency window ('most recent count messages'), which annotations do not convey, but it says nothing about how ordering interacts with a capped count or whether older messages are retrievable.
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 sentence, no filler, and the key scoping information (most recent, per-conversation, oldest-first order) is front-loaded. Nothing needs trimming and nothing essential is buried.
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?
An output schema exists, so return-value explanation is not required, and the tool is low complexity with only two parameters. The description covers the core behavior adequately; only edge cases (count exceeding available history, behavior when thread_id is invalid) are 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 description coverage is 0%, so the description must carry parameter meaning. It does clarify `count` as the number of most-recent messages and the returned ordering, but leaves the schema default of 20 unmentioned and says nothing about `thread_id` beyond the 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?
Specific verb ('Read') plus a precisely scoped resource ('the most recent `count` messages of one conversation'), which is clear enough to separate it from list_threads (enumerating conversations) and send_sms (writes). It does not name those siblings explicitly, but the resource framing makes the distinction inferable.
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?
No explicit when-to-use or when-not-to-use guidance and no mention of any alternative tool, despite having three siblings. The agent must infer from the name alone that this is the tool for reading messages within an already-known thread rather than listing threads.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_smsADestructive
Send an SMS (several numbers = group message) from the user's phone and number.
ONLY call after the user has explicitly approved this exact recipient list and text.
`to` takes phone numbers; resolve names with find_contact first.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | ||
| text | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint and openWorldHint, but the description adds the crucial behavioral gate that this must not be invoked without explicit user approval of the exact recipients and text, plus the fact that multiple numbers fan out to a group message. It does not cover delivery/rate-limit behavior, but the approval requirement is the highest-value disclosure 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?
Three short lines with zero padding; the action and the approval precondition are front-loaded before the contact-resolution hint. Every sentence 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?
An output schema exists, so return values need no explanation, and annotations already cover the safety profile. The description supplies the missing operational constraints (approval gate, group semantics, name resolution) needed to invoke this destructive, open-world tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry parameter meaning; it explains that 'to' holds phone numbers (not names) and that multiple values produce a group message, which is real semantics beyond the bare array-of-strings schema. 'text' is left implicit, though its name and string type make it self-evident.
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) and resource (SMS) plus the originating identity (user's phone and number), and clarifies the multi-recipient case as a group message. It also names find_contact, letting an agent distinguish this from the contact-resolution 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 an explicit precondition ('ONLY call after the user has explicitly approved this exact recipient list and text') and routes a prerequisite sub-task to the alternative tool ('resolve names with find_contact first'). When-to-use and which-sibling-to-use are both covered.
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.
4 tool updates
v0.1.0- First observed
find_contact - First observed
list_threads - First observed
read_thread - First observed
send_sms
TDQS
Scored across 4 tools
Each tool targets a clearly distinct action: listing threads, reading a single thread, finding contacts, and sending messages. There is no meaningful overlap between any pair.
All four tools use a consistent snake_case verb_noun pattern (list_threads, read_thread, find_contact, send_sms). The convention is predictable throughout.
Four tools is well-scoped for a focused SMS server, covering discovery, reading, contact lookup, and sending. Slightly minimal but each earns its place.
Core flows are covered: find contact, list threads, read a thread, send a message. Minor gaps exist around thread management (delete/archive, mark read) but typical agent workflows are supported.
Maintenance
Related MCP Connectors
MCP connector for iMessage & Contacts via a local Mac agent + Vercel relay
Drive WhatsApp from any MCP client: pair devices, send text and media, manage contacts and groups.
Your own WhatsApp as an MCP server: read, search and send from any MCP client.
The Mobile Text Alerts SMS MCP server enables your AI to send SMS messages & manage contacts
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables reading, searching, and sending iMessages directly from MCP-compatible clients by accessing the local macOS iMessage database, supporting conversations, attachments, and both individual and group chats.381 npm10MIT
- AlicenseNot gradedqualityDmaintenanceEnables sending and reading iMessages and SMS messages through the macOS Messages app via MCP.MIT
- 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.61-
- AlicenseBqualityDmaintenanceMCP server for sending SMS via the SMSPM API. Send transactional SMS from Claude Desktop, Cursor, Windsurf, Cline, or any MCP client.134 npmMIT