groupme-mcp-server
This server gives an AI assistant agentic tools to read and interact with a single GroupMe account's conversations.
List conversations – merge groups and DMs into one recency-sorted inbox with previews, member counts, and ids for chaining.
Read messages – page through a group or DM history, oldest first, with a cursor (
before_id/next_before_id) and optional concise or detailed formats.Get conversation context – fetch a group's metadata, member list, and recent messages in one call.
Search messages – search a conversation's history client-side by text and/or sender name, with honest reporting of scan limits.
Get highlights – see a group's most-liked messages and member summaries for a day, week, or month.
Send messages – post to a group or DM, optionally as a reply, optionally with a GroupMe-hosted image.
React to messages – like or unlike a specific message idempotently.
Provides tools for interacting with GroupMe, enabling listing conversations, reading and searching messages, fetching highlights, sending messages, and reacting to messages as the configured GroupMe account.
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., "@groupme-mcp-serversearch for "weekend plans" in my family group"
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.
groupme-mcp-server
An MCP server for GroupMe, built with FastMCP.
It is a set of agentic tools, not an endpoint wrapper: instead of mirroring the GroupMe API v3 route-for-route, each tool does one job an assistant actually needs — merging groups and DMs into a single inbox, paginating history with cursors, searching client-side because GroupMe has no search endpoint, and reporting honestly when a result is truncated.
Status: early. Read, search/highlights, and the core write tools (sending messages, likes) are implemented; image upload is not yet.
Tools
Tool | What it does |
| Merge groups and DMs into one recency-sorted list with last-message previews. |
| Read one group or DM conversation, oldest first, with a |
| One group's metadata, member list, and recent messages in a single call. |
| Search a conversation's history client-side (GroupMe has no search API), with honest scan accounting. |
| A group's top-liked messages for a day/week/month plus a member summary. |
| Post to a group or DM, optionally as a reply or with a GroupMe-hosted image. |
| Like or unlike one message (ids from |
The read tools accept response_format: "concise" (default, human-readable)
or "detailed" (full ids and metadata).
Related MCP server: Instagram DMs MCP
Connecting to the hosted server
The server is deployed on Prefect Horizon at:
https://groupme.fastmcp.app/mcpThe deployment is protected by Horizon's built-in auth: clients sign in via OAuth, and only users the deployment owner has authorized can connect — unauthenticated requests are rejected. Note that this is a single-tenant deployment (see Security): every authorized client acts as the one GroupMe account whose token is configured on the server.
Running locally
The package runs as a stdio MCP server. Get a GroupMe access token from https://dev.groupme.com (sign in and copy your access token), then:
GROUPME_ACCESS_TOKEN=... uvx groupme-mcp-serverOr configure an MCP client to launch it:
{
"mcpServers": {
"groupme": {
"command": "uvx",
"args": ["groupme-mcp-server"],
"env": {
"GROUPME_ACCESS_TOKEN": "your-token-from-dev.groupme.com"
}
}
}
}Configuration
Everything is configured through environment variables (GROUPME_* may also
come from a local .env file — see .env.example).
Variable | Default | Description |
| (unset) | GroupMe API token from https://dev.groupme.com. Optional at startup; required when a tool calls the API. |
|
| Verbosity of the server's own loggers: |
|
| GroupMe REST API base URL (override mainly for testing). |
|
| GroupMe image-upload service base URL. Reserved: unused until image upload is implemented. |
| (unset) | OTLP/HTTP collector endpoint. Setting it turns tracing on. |
| (unset) | Extra headers for the OTLP exporter (e.g. |
|
| The |
| (unset) | Set to |
|
| Verbosity of FastMCP's own |
Security
Single-tenant by design. The server holds exactly one GroupMe token and every tool acts as that token's owner — reading their conversations, posting as them, liking as them. Anyone allowed to connect (locally, or through Horizon's auth on the hosted deployment) gets that full identity; there is no per-client GroupMe account mapping.
The token never crosses the MCP boundary. Clients never send or receive it: the token lives server-side, goes to GroupMe only as the
X-Access-Tokenrequest header (never in URLs), is excluded from tool output and error messages, and is registered for redaction if OTel header capture is enabled.Hosted-deployment caveat. On Horizon, tool requests and responses pass through Prefect's infrastructure and may appear in its request/payload logs. Message content read or written through the hosted server is visible to whoever operates the deployment; run the server locally if that is not acceptable.
Report vulnerabilities through private vulnerability reporting, not public issues — see SECURITY.md.
Observability
Logs are structured single lines on stderr (stdout would corrupt the stdio transport), each carrying the current OTel
trace_id/span_idwhen a span is active.GROUPME_LOG_LEVELcontrols the server's own loggers.Traces are opt-in: when
OTEL_EXPORTER_OTLP_ENDPOINTis set (andOTEL_SDK_DISABLEDis not truthy), the server installs an OTLP/HTTP span exporter. FastMCP emits a span for everytools/call, and outbound GroupMe HTTP requests get client spans via instrumentedhttpx2transports — without an endpoint everything no-ops.
Development
Requires uv and Python 3.13+.
git clone https://github.com/oddrationale/groupme-mcp-server.git
cd groupme-mcp-server
uv sync --all-groups
uv run lefthook install # install the git hooksCommon tasks:
Command | What it does |
| Format. |
| Lint and autofix. |
| Type check. |
| Run tests. Fails below 100% coverage. |
| Run a subset without the coverage gate. |
| Opt-in live/e2e suites (see |
| See what Horizon sees. |
Coverage is enforced at 100% (branch coverage included). If a line is
genuinely untestable, exclude it deliberately with # pragma: no cover and say
why in the PR — do not lower the threshold.
Deployment
The hosted server is deployed on Prefect Horizon, which builds directly from this repository via its GitHub App.
Entrypoint:
src/groupme_mcp_server/server.py:mcpDependencies: installed with
uv sync --frozen --no-dev, souv.lockmust be committed and current or the build failsEnvironment variables: registered in the Horizon UI (
GROUPME_ACCESS_TOKENat minimum)Auth: Horizon's built-in OAuth — clients must present a bearer token
The production target tracks main and deploys only after CI passes; every
pull request gets its own preview deployment. There is no deploy step in GitHub
Actions — CI gates quality and security, Horizon does the shipping.
Contributing
See CONTRIBUTING.md.
License
MIT © Dariel Dato-on
Available Tools
7 toolsget_conversation_contextGet Conversation ContextARead-onlyIdempotent
Get one group's metadata, member list, and recent messages in one call.
Use this to orient yourself in a group before reading further or
replying: it bundles what would otherwise take several calls. For
direct-message chats or for paging deeper into history, use
read_messages instead.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | Yes | The group's id (from ``list_conversations``). | |
| response_format | No | ``"concise"`` (default) for names, nicknames, roles, and relative ages; ``"detailed"`` adds user ids, the share URL, and ISO timestamps. | concise |
| recent_message_count | No | How many recent messages to include (1-100). |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| members | No | |
| group_id | Yes | |
| image_url | No | |
| share_url | No | |
| updated_at | No | |
| description | No | |
| last_active | No | |
| member_count | No | |
| message_note | No | |
| creator_user_id | No | |
| recent_messages | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the bar is lower. The description still adds real behavioral context: it bundles three kinds of data that 'would otherwise take several calls' and is scoped to group conversations only, not DMs. It does not mention pagination or result limits, but recent_message_count's 1-100 bound is in the 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?
Three short sentences, no filler. The primary capability is front-loaded and the routing guidance follows immediately after. 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 not be explained, and the description still summarizes what comes back (metadata, members, recent messages). Combined with 100% schema coverage and full annotation coverage, an agent has everything needed to select and invoke this 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 description coverage is 100% and each parameter is documented in the schema, including the concise/detailed enum semantics and the 1-100 message bound. The description adds no parameter-level detail beyond what the schema already provides, 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 and resource (get one group's metadata, member list, recent messages) plus the key scope constraint that it does it 'in one call'. This distinguishes it clearly from read_messages and list_conversations without needing to open 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 situation to use it ('orient yourself in a group before reading further or replying') and the situations not to ('direct-message chats', 'paging deeper into history'), routing the agent to the named alternative read_messages. When/when-not/alternative are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_highlightsGet HighlightsARead-onlyIdempotent
Summarize what mattered in a group: its most-liked recent messages.
Use this to catch up on a busy group without reading everything: it wraps GroupMe's likes leaderboard into the period's top-liked messages (sender, like count, text preview) plus a per-member summary of who was most liked and most represented among them. The member summary covers only the leaderboard's messages, not the group's full history. The leaderboard endpoint is undocumented; if GroupMe has retired it, this tool fails with guidance rather than guessing.
| Name | Required | Description | Default |
|---|---|---|---|
| period | No | The leaderboard window: ``"day"``, ``"week"`` (default), or ``"month"``. | week |
| group_id | Yes | The group's id (from ``list_conversations``). | |
| response_format | No | ``"concise"`` (default) for names, previews, and relative ages; ``"detailed"`` adds user ids and ISO timestamps. | concise |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | |
| period | Yes | |
| group_id | Yes | |
| top_members | Yes | |
| top_messages | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnly, idempotent, openWorld), the description discloses a real data-scope limitation — the member summary covers only leaderboard messages, not full history — and an error behavior: the undocumented endpoint fails with guidance rather than guessing. These are exactly the traits 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?
Three compact movements — what it does, when to use it, and the caveats — front-loaded with the core purpose and no filler sentences. Every clause adds 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 an output schema present, return formatting need not be explained, yet the description still previews contents (sender, like count, text preview) and covers the scope limitation and failure mode. 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% with enums documented for period and response_format, so the schema carries parameter semantics. The description adds little beyond 'the period's top-liked messages,' which merely restates the period 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?
The description states a specific verb ('summarize') and resource ('what mattered in a group: its most-liked recent messages'), and distinguishes itself from read_messages by framing the tool as catching up 'without reading everything.' An agent can tell what this returns 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?
'Use this to catch up on a busy group without reading everything' gives clear context for when to reach for it, and implicitly contrasts with read_messages/search_messages. It stops short of naming an explicit alternative or stating when NOT to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_conversationsList ConversationsARead-onlyIdempotent
List the user's GroupMe conversations, most recently active first.
Use this first, whenever you need to find a conversation or the ids the
other tools take: it merges groups and direct-message chats into one
recency-sorted list with last-message previews and member counts. Every
entry carries the group_id or other_user_id that read_messages
and get_conversation_context need.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Which conversations to include - ``"groups"``, ``"dms"``, or ``"all"`` (default). | all |
| limit | No | Maximum conversations to return (1-100). | |
| response_format | No | ``"concise"`` (default) for names, previews, and relative ages; ``"detailed"`` adds descriptions, share URLs, creator ids, and ISO timestamps. | concise |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | |
| count | Yes | |
| conversations | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/destructive=false, so safety is covered. The description adds genuine behavioral context beyond that: the recency sort order, merged group/DM listing, last-message previews, member counts, and the fact that each entry carries the ids other tools need.
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?
Two sentences, front-loaded with the core action, then the routing rationale. No filler, no repetition of the title or 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 an output schema present and annotations covering the safety profile, the description is nearly complete; it even sketches the return shape. Missing only pagination/truncation behavior given the 1-100 limit parameter, which is a minor 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?
Schema description coverage is 100%, so 'kind', 'limit', and 'response_format' are already fully documented with defaults and enums. The description adds no param-level meaning (e.g., no guidance on which kind to pick), 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 and resource ('List the user's GroupMe conversations') plus the ordering ('most recently active first') and scope ('merges groups and direct-message chats into one recency-sorted list'). An agent can distinguish this from siblings like search_messages or read_messages 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?
Explicitly says 'Use this first, whenever you need to find a conversation or the ids the other tools take,' naming the downstream consumers (read_messages, get_conversation_context). This gives a clear when-to-use condition and routes the agent to the correct entry point.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
react_to_messageReact To MessageAIdempotent
Like a GroupMe message, or remove your like from one.
Use this to react to a specific message on the authenticated user's
behalf — acknowledging something without posting a reply.
Both actions are idempotent: liking an already-liked message (or
unliking one you never liked) leaves it in the requested state. Ids come
from read_messages with response_format="detailed": use its
conversation_id (a group id, or a composite direct-chat id like
"123+456") and message id.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | ``"like"`` to like it, ``"unlike"`` to remove your like. | |
| message_id | Yes | The message to react to. | |
| conversation_id | Yes | The conversation holding the message. |
Output Schema
| Name | Required | Description |
|---|---|---|
| action | Yes | |
| message_id | Yes | |
| confirmation | Yes | |
| conversation_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true, destructiveHint=false, readOnlyHint=false, openWorldHint=true. The description earns credit by spelling out what idempotency concretely means ('liking an already-liked message ... leaves it in the requested state') and by noting the action is on the authenticated user's behalf. It does not mention rate limits or failure behavior, but the annotation bar is already met.
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 usage context and id-sourcing details. Every sentence carries information; the RST double-backtick artifacts and slight redundancy around message_id are the only minor drag.
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. Combined with annotations, the description covers the action semantics, idempotency, auth scope, and how to source the required ids — 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. The description adds genuine meaning beyond the schema by explaining where the ids originate (read_messages with response_format='detailed') and warning that conversation_id may be a group id or a composite direct-chat id like '123+456'.
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 opening sentence gives a specific verb+resource ('Like a GroupMe message, or remove your like from one') and the scope is unambiguous. It is clearly distinguishable from send_message because the follow-up states the purpose is 'acknowledging something without posting a reply.'
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 clear positive context ('react to a specific message on the authenticated user's behalf') and implicitly routes away from send_message by noting no reply is posted. It also tells the agent where to obtain ids. It never explicitly names an alternative tool or states a when-not-to-use condition, so it stops 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.
read_messagesRead MessagesARead-onlyIdempotent
Read messages from one GroupMe conversation, oldest first.
Use this to read or page through the history of a specific group or
direct-message chat once you know its id (from list_conversations).
Sender names are resolved and attachments are normalized (image URLs,
reply/mention summaries). An empty page is a normal answer, not an
error: it means the conversation has no messages in the requested range.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum messages to return (1-100). Direct chats may return fewer per page regardless of ``limit``. | |
| since_id | No | Read the most recent messages newer than this message id. | |
| before_id | No | Read messages older than this message id (use the previous page's ``next_before_id``). At most one of ``before_id`` and ``since_id`` may be given. | |
| conversation | Yes | Which conversation to read: ``{"kind": "group", "group_id": ...}`` or ``{"kind": "direct", "other_user_id": ...}``. | |
| response_format | No | ``"concise"`` (default) for sender names, text, relative ages, and like counts; ``"detailed"`` adds sender ids, conversation ids, and ISO timestamps. | concise |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | |
| messages | Yes | |
| next_before_id | No |
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 real value beyond that: sender names are resolved, attachments are normalized into image URLs and reply/mention summaries, and an empty page is explicitly a normal answer rather than an error.
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 the verb and scope, then usage, then normalization and empty-page semantics. Every sentence carries information an agent needs and nothing is repeated from 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?
An output schema exists, so return values need not be explained. The description covers the remaining agent-facing concerns for this tool: how to obtain the conversation id, how paging works, what normalization to expect, and how to interpret an empty 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 description coverage is 100%, so limit, since_id, before_id, conversation and response_format are already fully documented in the schema, including the mutual exclusivity of before_id and since_id. The description adds no syntax or format detail beyond the schema, so the baseline 3 is correct.
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 ('Read messages from one GroupMe conversation') plus a scoping detail ('oldest first') that an agent can act on. It also anchors the tool to the list_conversations sibling for obtaining the conversation id, distinguishing it from search_messages and get_conversation_context.
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: use it to read or page through one conversation's history once the id is known from list_conversations, and notes that empty pages are normal. It does not explicitly state when to prefer search_messages or get_highlights instead, so it falls short of a full when/when-not/alternative statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_messagesSearch MessagesARead-onlyIdempotent
Search one conversation's message history for matching messages.
Use this to find specific messages ("who mentioned pizza?", "what did
Ada say last week?") instead of paging manually with read_messages.
GroupMe has no search API, so this scans backwards from the newest
message, matching query against message text and sender_name
against sender names (both case-insensitive substrings), until limit
matches are found, the oldest message is reached, or
max_messages_scanned messages have been examined. The result reports
exactly how far the scan got — check oldest_message_reached and
note before concluding something was never said.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Stop after this many matches (1-100). | |
| query | Yes | Text to look for in message text. May be empty only when ``sender_name`` is given (a sender-only search). | |
| sender_name | No | Only match messages whose sender's display name contains this. | |
| conversation | Yes | Which conversation to search: ``{"kind": "group", "group_id": ...}`` or ``{"kind": "direct", "other_user_id": ...}`` (ids from ``list_conversations``). | |
| response_format | No | ``"concise"`` (default) for sender names, text, relative ages, and like counts; ``"detailed"`` adds sender ids, conversation ids, and ISO timestamps. | concise |
| max_messages_scanned | No | Stop after examining this many messages (1-5000); a hit cap is reported in ``note``, never silent. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | |
| count | Yes | |
| matches | Yes | |
| next_before_id | No | |
| messages_scanned | Yes | |
| oldest_message_reached | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover safety (readOnly/idempotent/non-destructive/openWorld); the description adds substantial mechanics the annotations cannot: no native search API, backward scan from newest, case-insensitive substring matching, the three termination conditions, and the caveat to inspect oldest_message_reached and note before concluding a message was never sent. This is exactly the kind of result-interpretation 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?
Front-loaded with purpose, then usage, then mechanics, in three tight paragraphs with no filler. Slightly dense and longer than strictly necessary, but nearly every clause carries operational 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?
Covers the full picture for a six-parameter search tool: what it does, when to prefer it, how matching and scanning terminate, and how to read the result fields. An output schema exists, so the description correctly stops short of enumerating return structure while still flagging the fields that change interpretation.
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 goes beyond it by explaining that query matches message text and sender_name matches sender names, both as case-insensitive substrings, and by framing limit and max_messages_scanned as scan-stopping conditions rather than just numeric bounds.
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 (search), a bounded resource (one conversation's message history), and the match target, which cleanly separates it from read_messages and get_conversation_context. The scope word 'one conversation' prevents the agent from assuming a global search.
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 this to find specific messages instead of paging manually with read_messages, backed by concrete example queries. The when-to-use condition and the alternative it replaces are both named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_messageSend MessageA
Send a message to a GroupMe group or direct-message chat.
Use this to post as the authenticated user once you know where to send
(ids come from list_conversations). Each call sends a new message —
calling twice posts twice. To reply to a specific message, pass its id
(from read_messages) as reply_to_message_id.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | The message text, at most 1000 characters. May be empty only when ``image_url`` is given. | |
| image_url | No | Image to attach. Only GroupMe image-service URLs (``https://i.groupme.com/...``) are supported for now; other image URLs are rejected with guidance. | |
| conversation | Yes | Where to send: ``{"kind": "group", "group_id": ...}`` or ``{"kind": "direct", "other_user_id": ...}``. | |
| reply_to_message_id | No | Id of the message being replied to, attached as a GroupMe reply so clients render it threaded. |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | |
| text | Yes | |
| sent_at | Yes | |
| group_id | No | |
| message_id | Yes | |
| attachments | No | |
| other_user_id | No | |
| conversation_id | No |
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 reinforces non-idempotency in plain language ('calling twice posts twice') and notes it posts 'as the authenticated user', adding auth context, but says nothing about failure modes, rate limits, or the open-world/external nature beyond the annotation.
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/paragraphs, front-loaded with purpose, then prerequisites, then the reply variant. No filler and no repetition of schema details.
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. For a non-idempotent send tool, the description covers target-dependent ids, the double-send hazard, and the reply option — everything an agent needs 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 description coverage is 100%, so all four parameters are already documented, including the conversation oneOf shape and the image_url restriction. The description only restates the reply_to_message_id usage and id provenance, adding little beyond the schema's own text; 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 ('send') and resource ('a message to a GroupMe group or direct-message chat'), covering both target types. An agent can immediately distinguish it from siblings like read_messages or list_conversations, which are only mentioned as id sources.
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 ('once you know where to send', ids from list_conversations), warns that each call posts a new message, and names the alternative path for replies ('to reply to a specific message, pass its id'). Prerequisite ordering and the reply use-case are both spelled out.
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.
7 tool updates
v0.2.0- First observed
get_conversation_context - First observed
get_highlights - First observed
list_conversations - First observed
react_to_message - First observed
read_messages - First observed
search_messages - First observed
send_message
TDQS
Scored across 7 tools
Most tools have clearly distinct purposes: search vs. paging vs. highlights vs. sending vs. reacting. The only mild overlap is read_messages vs. get_conversation_context, since both return recent messages, but the descriptions explicitly differentiate orientation-in-a-group from deep paging.
All seven tools follow a consistent snake_case verb_noun pattern (list_conversations, read_messages, get_conversation_context, search_messages, get_highlights, send_message, react_to_message). No style mixing or vague verbs.
Seven tools is well-scoped for a messaging integration, with discovery, reading, searching, summarizing, sending, and reacting each earning a place. Nothing feels redundant or bloated.
Covers the core lifecycle: find conversations, read, search, summarize, send, and react. Group or conversation creation, membership management, message deletion, and media sending are absent, but agents can work around these for typical read-and-post flows.
Maintenance
Related MCP Connectors
Messaging tools for AI agents: send messages, manage chats, groups and channels.
- UproarOAuthchat.uproar
Chat where AI agents are first-class members, with their own identity and permissions.
Carbon Voice MCP serves as a bridge that connects AI assistants like ChatGPT, Claude, and Cursor to a user's Carbon Voice account, turning voice messages and conversations into a private, on-demand knowledge base. It provides 28 specialized tools for comprehensive voice messaging management, including creating and sending messages, accessing conversation history with instant transcription, running AI actions (summarization, TLDR generation, meeting notes), and managing workspace collaboration through folders, contacts, and team communications.
Instagram for AI agents: publish, read comments and DMs, insights, and engage from your account.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI models to interact with messages from various messaging platforms (Mobile, Mail, WhatsApp, LinkedIn, Slack, Twitter, Telegram, Instagram, Messenger) through a standardized interface.316MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to read, send, and manage Instagram direct messages, including viewing conversations, sending DMs to users, reacting to messages, and searching for users by username.10-
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to read, search, and send iMessages with features like contact name resolution, session grouping, and attachment listing. It provides intent-aligned tools to efficiently navigate conversation history and manage messages through natural language queries.6MIT
- FlicenseBqualityBmaintenanceAn MCP server that integrates with the GroupMe API v3 to allow AI assistants to manage groups, messages, members, and bots. It enables comprehensive interaction with the GroupMe platform, including sending direct messages, liking content, and managing user blocks.29-