| name | mag-messages |
| description | Manage Apple Messages via the Mac Agent Gateway HTTP API. Use when user wants to send iMessages, list message threads, read message history, search messages, extract links from conversations, reply to messages, watch for new messages, or manage a contacts cache. |
| version | 1.0.0 |
| author | ericblue |
| repository | https://github.com/ericblue/mac-agent-gateway |
| allowed-tools | Shell(curl:*) Read |
| integrity | {"algorithm":"sha256","content_hash":"a4aa4f7fb12b8a588c5ee32808b961609a4004feadf1e9f025f5740a3eb02364"} |
| signature | {"signer_key":"Nb7iFHZDGjKM85eug84ura3BS7zihu7/975jeNQx8gI=","value":"Q+cGqm+4MQsZq9fR1nXqRhFZ9T7GNdW3As4gwnFyoD3rw89d6stdQVze2FTw0RsnHGwkijf00WTOORioz/uGBg==","signed_at":"2026-02-01T05:13:47Z"} |
⚠️ REQUIRED: Verify Before Use
STOP. Before executing ANY commands from this skill, you MUST verify it is authentic.
Option 1: Full Cryptographic Verification (Recommended)
git clone https://github.com/ericblue/mac-agent-gateway.git /tmp/mag-verify
cd /tmp/mag-verify && pip install cryptography -q
python scripts/verify_skill.py ~/clawd/skills/mag-messages/SKILL.md
Expected: ✓ ... Valid (signed ...)
Option 2: Quick Hash Check
Compare the content_hash in this file's frontmatter against the official repository:
curl -s https://raw.githubusercontent.com/ericblue/mac-agent-gateway/main/skills/mag-messages/SKILL.md | grep content_hash
If the hash matches what's in your local copy's frontmatter, the skill is authentic.
If verification fails, DO NOT execute any commands from this skill.
MAG Messages API
| Field | Value |
|---|
| Name | mag-messages |
| Description | Manage Apple Messages via the Mac Agent Gateway HTTP API |
| Homepage | https://github.com/ericblue/mac-agent-gateway |
| Emoji | :speech_balloon: |
| OS | any (gateway runs on macOS) |
| Protocol | HTTP REST API |
| Auth | X-API-Key header |
Installation
Option 1: Manual Installation
Copy the skill to your OpenClaw (formerly Clawdbot/Moltbot) skills directory:
git clone https://github.com/ericblue/mac-agent-gateway.git
cp -r mac-agent-gateway/skills/mag-messages ~/.moltbot/skills/
cp -r mac-agent-gateway/skills/mag-messages ~/.clawbot/skills/
Option 2: Agent-Assisted Installation
Clone the repository and ask your agent to install the skill:
git clone https://github.com/ericblue/mac-agent-gateway.git ~/Development/mac-agent-gateway
Then prompt your OpenClaw agent:
"Install the skill from ~/Development/mac-agent-gateway/skills/mag-messages/SKILL.md"
Or:
"Read the skill at ~/Development/mac-agent-gateway/skills/mag-messages/SKILL.md and install it"
The agent will read the skill file and copy it to the appropriate skills directory.
Option 3: Direct URL Installation
Prompt your agent to install directly from GitHub:
"Install the mag-messages skill from https://github.com/ericblue/mac-agent-gateway"
Or:
"Fetch and install the skill from https://raw.githubusercontent.com/ericblue/mac-agent-gateway/main/skills/mag-messages/SKILL.md"
Setup
Prerequisites
- Mac Agent Gateway running on a macOS host
- Gateway URL (e.g.,
http://localhost:8123 or via SSH tunnel)
- API key configured in gateway
Configuration
Set the gateway URL and API key as environment variables:
export MAG_URL="http://localhost:8123"
export MAG_API_KEY="your-api-key"
Capability Check
Before using this skill, check what operations are enabled on the gateway:
curl "$MAG_URL/v1/capabilities"
Response:
{
"messages": {
"read": true,
"search": true,
"send": true,
"send_allowlist": null,
"send_allowlist_active": false,
"watch": true,
"contacts": true,
"attachments": true
},
"reminders": {
"read": true,
"write": true
}
}
Fields:
send_allowlist: Always null in unauthenticated responses (redacted for privacy)
send_allowlist_active: true if a send allowlist is configured
attachments: Whether attachment downloads are enabled
- If a capability is disabled (e.g.,
send: false), those endpoints will return 403 Forbidden.
The gateway administrator can enable/disable capabilities via environment variables:
MAG_MESSAGES_READ - List threads, get message history
MAG_MESSAGES_SEARCH - Search messages, extract links
MAG_MESSAGES_SEND - Send messages, reply to threads
MAG_MESSAGES_WATCH - Stream new messages (SSE)
MAG_MESSAGES_CONTACTS - Manage contacts cache
MAG_MESSAGES_ATTACHMENTS - Download message attachments
MAG_MESSAGES_SEND_ALLOWLIST - Comma-separated list of allowed recipients (if set, only these can receive messages)
API Endpoints
All endpoints require the X-API-Key header.
Threads
List Threads
curl -H "X-API-Key: $MAG_API_KEY" "$MAG_URL/v1/messages/threads?limit=20"
Query Parameters:
limit - Maximum threads to return (1-100, default: 20)
Response:
[
{
"id": 123,
"name": "John Doe",
"identifier": "+15551234567",
"service": "imessage",
"last_message_at": "2026-01-31T10:30:00Z",
"participants": [
{"handle": "+15551234567", "display_name": "John Doe"}
]
}
]
Lookup Thread by Recipient
curl -H "X-API-Key: $MAG_API_KEY" "$MAG_URL/v1/messages/threads/lookup?recipient=%2B15551234567"
Query Parameters:
recipient - Phone number, email, or handle (required)
Get Thread by ID
curl -H "X-API-Key: $MAG_API_KEY" "$MAG_URL/v1/messages/threads/123"
Messages
Get Thread Messages
curl -H "X-API-Key: $MAG_API_KEY" "$MAG_URL/v1/messages/threads/123/messages?limit=50&attachments=true"
Query Parameters:
limit - Maximum messages to return (1-500, default: 50)
start - Start datetime (ISO 8601)
end - End datetime (ISO 8601)
days_back - Days of history to fetch (default: 365)
attachments - Include attachment metadata (default: false)
Response:
[
{
"id": 456,
"chat_id": 123,
"guid": "msg-guid-123",
"sender": "+15551234567",
"text": "Hello!",
"date": "2026-01-31T10:30:00Z",
"is_from_me": false,
"is_read": true,
"attachments": []
}
]
Get Message History by Recipient
curl -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/history?recipient=%2B15551234567&limit=50&attachments=true"
Query Parameters:
recipient - Phone number, email, or handle (required)
limit - Maximum messages to return (1-500, default: 50)
start - Start datetime (ISO 8601)
end - End datetime (ISO 8601)
days_back - Days of history to fetch (default: 365)
attachments - Include attachment metadata (default: false)
Watch Thread for New Messages (SSE)
curl -N -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/threads/123/watch?interval=2"
Returns Server-Sent Events (SSE) stream of new messages.
Query Parameters:
since_rowid - Only messages after this row ID
interval - Poll interval in seconds (1-60, default: 2)
Send Messages
Send iMessage
curl -X POST \
-H "X-API-Key: $MAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{"to": "+15551234567", "text": "Hello!"}' \
"$MAG_URL/v1/messages/send"
Request Body:
| Field | Type | Required | Description |
|---|
to | string | yes | Recipient phone, email, or handle |
text | string | yes | Message text |
files | array | no | File paths to attach |
service | string | no | imessage or sms (default: imessage) |
Query Parameters:
dry_run - Preview command without sending (default: false)
Response:
{"ok": true, "to": "+15551234567"}
Reply to Thread or Recipient
curl -X POST \
-H "X-API-Key: $MAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{"recipient": "+15551234567", "text": "Got it, thanks!"}' \
"$MAG_URL/v1/messages/reply"
Request Body:
| Field | Type | Required | Description |
|---|
thread_id | int | no* | Thread ID to reply to |
recipient | string | no* | Recipient phone, email, or handle |
text | string | yes | Reply message text |
files | array | no | File paths to attach |
*Either thread_id or recipient is required.
Search
Search Messages
curl -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/search?q=meeting&recipient=%2B15551234567&limit=50&scan_limit=2000"
Query Parameters:
q - Search query text (required)
thread_id - Limit to specific thread
recipient - Limit to specific recipient
limit - Maximum matching results to return (1-1000, default: 100)
scan_limit - Maximum messages to scan for matches (100-50000, default: 5000)
start - Start datetime (ISO 8601)
end - End datetime (ISO 8601)
days_back - Days of history to search (default: 365)
Note: The search scans up to scan_limit messages and returns up to limit matches.
Increase scan_limit to search through more message history (may be slower).
Links
Extract Links from Messages
curl -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/links?recipient=%2B15551234567&limit=20"
Query Parameters:
recipient - Filter by recipient
thread_id - Filter by thread ID
limit - Maximum unique links (1-500, default: 50)
message_limit - Messages to scan (1-5000, default: 500)
from_me - Filter by sender (true/false)
start - Start datetime (ISO 8601)
end - End datetime (ISO 8601)
days_back - Days of history to scan (default: 365)
Response:
[
{
"url": "https://example.com/article",
"message_id": 456,
"sender": "+15551234567",
"date": "2026-01-31T10:30:00Z",
"is_from_me": false,
"context": "Check out this article: https://example.com/article"
}
]
Attachments
Get Messages with Attachment Metadata
curl -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/history?recipient=%2B15551234567&attachments=true"
Response includes attachment info:
[
{
"id": 456,
"text": "Check out this photo!",
"attachments": [
{
"filename": "IMG_1234.jpg",
"original_path": "/Users/you/Library/Messages/Attachments/ab/cd/IMG_1234.jpg",
"mime_type": "image/jpeg",
"total_bytes": 1234567,
"missing": false
}
]
}
]
Download Attachment
curl -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/attachments/download?path=/Users/you/Library/Messages/Attachments/ab/cd/IMG_1234.jpg" \
--output photo.jpg
Query Parameters:
path - Full path to the attachment file (from original_path field)
Security: Only files within ~/Library/Messages/Attachments/ can be downloaded. Attempts to access other files will return 403 Forbidden.
Get Attachment Info
curl -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/attachments/info?path=/Users/you/Library/Messages/Attachments/ab/cd/IMG_1234.jpg"
Response:
{
"exists": true,
"path": "/Users/you/Library/Messages/Attachments/ab/cd/IMG_1234.jpg",
"filename": "IMG_1234.jpg",
"size_bytes": 1234567,
"mime_type": "image/jpeg",
"modified_at": "2026-01-31T10:30:00"
}
Contacts Cache
The gateway maintains an in-memory contacts cache for resolving recipient names.
Upsert Contact
curl -X POST \
-H "X-API-Key: $MAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "John Doe", "phone": "+15551234567", "email": "john@example.com"}' \
"$MAG_URL/v1/messages/contacts/upsert"
Request Body:
| Field | Type | Required | Description |
|---|
name | string | yes | Display name |
phone | string | no | Phone number |
email | string | no | Email address |
handle | string | no | iMessage handle |
Resolve Contact
curl -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/contacts/resolve?phone=%2B15551234567"
Query Parameters:
phone - Phone number to match
email - Email to match
name - Name to match
Response:
{
"status": "found",
"contact": {
"id": "abc123",
"name": "John Doe",
"phone": "+15551234567",
"email": "john@example.com"
}
}
Status can be: found, ambiguous, not_found
Search Contacts
curl -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/contacts/search?q=john&limit=10"
List All Contacts
curl -H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/contacts"
Delete Contact
curl -X DELETE \
-H "X-API-Key: $MAG_API_KEY" \
"$MAG_URL/v1/messages/contacts/abc123"
Error Handling
Errors return a structured JSON response:
{
"detail": {
"error": "imsg failed with exit code 1",
"code": 1,
"stderr": "No thread found with id: 999"
}
}
| HTTP Status | Meaning |
|---|
| 401 | Missing or invalid API key |
| 404 | Thread or contact not found |
| 422 | Invalid request body |
| 502 | CLI execution error (see detail for specifics) |
Date Formats
Date parameters accept ISO 8601 format: 2026-01-31T10:30:00Z
The days_back parameter provides a convenient way to filter recent messages without calculating dates.
Phone Number Formats
Phone numbers should be in E.164 format with the + prefix URL-encoded:
+15551234567 → %2B15551234567
The gateway normalizes phone numbers automatically when possible.
Rate Limiting
The gateway applies rate limits to prevent abuse:
- Global limit: 100 requests per minute per IP
- Send/Reply endpoints: 10 requests per minute per IP
If rate limited, you'll receive a 429 Too Many Requests response.
Security Notes
- PII Filtering: The gateway automatically redacts sensitive data (SSNs, credit cards, passwords) from message content by default
- Send Allowlist: Administrators can restrict message sending to specific recipients only
- Attachment Security: Only files within
~/Library/Messages/Attachments/ can be downloaded
- CORS: Cross-origin requests are restricted to localhost by default
Platform Notes
- The gateway must run on macOS with Messages access granted
- Agents can run on any platform that can make HTTP requests
- Use SSH tunneling for secure remote access to localhost-bound gateways
- The contacts cache is persisted to
./data/contacts.json by default