Skip to main content
Glama
whirlwin

google-messages-for-web-mcp

by whirlwin
README.md
# google-messages-for-web-mcp

An MCP server (stdio) that reads and sends messages in [Google Messages for web](https://messages.google.com/web/conversations) by driving your already logged-in Chrome tab through the `chromefile` CLI. Not affiliated with Google.

## Requirements

- macOS
- Chrome with [chromefile](https://github.com/whirlwin/chromefile) installed
- A Messages for web tab paired with your phone (one is opened in the background if missing, but pairing is up to you)
- Node >= 24

## Install

```sh
npm install -g github:whirlwin/google-messages-for-web-mcp
# or
git clone https://github.com/whirlwin/google-messages-for-web-mcp && cd google-messages-for-web-mcp && npm i && npm run build
```

Register with Claude Code:

```sh
claude mcp add --scope user google-messages -- google-messages-for-web-mcp
```

Set `CHROMEFILE_BIN` if `chromefile` is not on your `PATH`.

## Tools

| Tool | Description |
|------|-------------|
| `status` | Is chromefile reachable, is a Messages tab open, is it ready or does it need pairing |
| `list_conversations` | `limit` (default 25): id, name, snippet, time, unread, pinned, muted (read only) |
| `read_messages` | `conversation_id`, `limit` (default 30): last messages in chronological order. Navigates the Messages tab to the conversation, which marks it read |
| `send_message` | `conversation_id`, `text` (max 2000 chars): types into the compose box, presses Enter (a trusted key event via CDP, since the app ignores synthetic clicks), returns `sent: true` once the new bubble appears (not confirmed delivery; see `status`). After an error that says the message may have been sent, do not retry |

## Security

- Incoming SMS and RCS text is untrusted input and can carry prompt injection. Every tool description says so.
- This server combines private data, untrusted content and an outbound send channel. Keep `send_message` behind per-call approval and never auto-approve it.
- Only one Messages for web session is active at a time. This server uses your existing tab and never clicks "Use here" or pairs for you; it returns an error telling you to do it.
- Conversation ids are validated against `^[A-Za-z0-9_-]+$` and all values reach the page as JSON literals, never as raw source.

## How it works

Each tool runs `chromefile call page.eval` against the Messages tab. Sending also uses `chromefile call page.cdp` to dispatch a trusted Enter key in the compose box. The functions in `src/page.ts` run inside the page and are serialised with `fn.toString()`. They rely on the app's `data-e2e-*` attributes and custom elements (`a[data-e2e-conversation]`, `mws-message-wrapper`, the compose box and send button). These selectors are reverse engineered and will break when Google changes the UI.

## Testing

```sh
npm test        # unit tests against a synthetic DOM fixture (happy-dom), no browser needed
npm run lint    # typecheck
```

End-to-end, against your real tab (not part of `npm test`):

```sh
GM_E2E_CONVERSATION=<conversation id> npm run test:e2e
GM_E2E_CONVERSATION=<conversation id> GM_E2E_SEND_TEXT="test" npm run test:e2e   # also sends a real message
```

## Alternatives

[openmessage](https://github.com/maxghenis/openmessage) talks to Google Messages at the protocol level (Go, via mautrix/gmessages libgm, AGPL-3.0) and needs no browser tab.

## License

MIT

Maintenance

ActivityMaintained
ResponsivenessNo issues