fastmail-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -0
- package/index.ts +58 -0
- package/openclaw.plugin.json +31 -0
- package/package.json +38 -0
- package/skills/fastmail/SKILL.md +136 -0
- package/src/auth.ts +27 -0
- package/src/formatters.ts +321 -0
- package/src/mcp-client.ts +150 -0
- package/src/tools/calendar.ts +77 -0
- package/src/tools/contacts.ts +55 -0
- package/src/tools/email.ts +493 -0
- package/src/tools/memo.ts +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# fastmail-cli
|
|
2
|
+
|
|
3
|
+
OpenClaw plugin for Fastmail email, contacts, and calendar. Provides 36 agent tools backed by a persistent in-process MCP connection for token-efficient output (5-7x savings vs raw JSON).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
openclaw plugins install fastmail-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
1. **Remote MCP Server**: Deploy the [fastmail-mcp-remote](https://github.com/omarshahine/fastmail-mcp-remote) Worker to Cloudflare.
|
|
14
|
+
|
|
15
|
+
2. **Get a Bearer Token**: Authenticate via the CLI to obtain a token:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
alias fastmail="npx tsx ~/path/to/fastmail-mcp-remote/cli/main.ts"
|
|
19
|
+
fastmail auth --url https://your-worker.example.com --team myteam
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The token is saved to `~/.config/fastmail-cli/config.json`. Copy the `bearerToken` value for plugin configuration.
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
Both fields are **required** in your OpenClaw workspace config:
|
|
27
|
+
|
|
28
|
+
| Key | Description |
|
|
29
|
+
|-----|-------------|
|
|
30
|
+
| `workerUrl` | URL of your deployed Fastmail MCP Worker |
|
|
31
|
+
| `bearerToken` | Bearer token from `fastmail auth` (each user needs their own) |
|
|
32
|
+
|
|
33
|
+
Each workspace can have different credentials, enabling multi-user setups on the same machine.
|
|
34
|
+
|
|
35
|
+
## Tools
|
|
36
|
+
|
|
37
|
+
### Email Read (11 tools, always available)
|
|
38
|
+
|
|
39
|
+
- `fastmail_inbox` - Recent inbox emails
|
|
40
|
+
- `fastmail_get_email` - Read a single email
|
|
41
|
+
- `fastmail_search_emails` - Search with text and filters (sender, date, unread, etc.)
|
|
42
|
+
- `fastmail_get_thread` - Conversation thread
|
|
43
|
+
- `fastmail_list_mailboxes` - List mailboxes
|
|
44
|
+
- `fastmail_get_mailbox_stats` - Mailbox statistics
|
|
45
|
+
- `fastmail_get_account_summary` - Account overview
|
|
46
|
+
- `fastmail_list_identities` - Sending identities
|
|
47
|
+
- `fastmail_get_attachments` - Email attachments
|
|
48
|
+
- `fastmail_download_attachment` - Download attachment
|
|
49
|
+
- `fastmail_get_inbox_updates` - Incremental sync
|
|
50
|
+
|
|
51
|
+
### Email Write (3 tools, optional)
|
|
52
|
+
|
|
53
|
+
- `fastmail_send_email` - Send email
|
|
54
|
+
- `fastmail_create_draft` - Create draft
|
|
55
|
+
- `fastmail_reply_to_email` - Reply to email
|
|
56
|
+
|
|
57
|
+
### Email Organize (6 tools, optional)
|
|
58
|
+
|
|
59
|
+
- `fastmail_mark_read` - Mark as read
|
|
60
|
+
- `fastmail_mark_unread` - Mark as unread
|
|
61
|
+
- `fastmail_flag` - Flag (star)
|
|
62
|
+
- `fastmail_unflag` - Unflag (unstar)
|
|
63
|
+
- `fastmail_delete` - Delete (trash)
|
|
64
|
+
- `fastmail_move` - Move to mailbox
|
|
65
|
+
|
|
66
|
+
### Email Bulk (6 tools, optional)
|
|
67
|
+
|
|
68
|
+
- `fastmail_bulk_read` - Bulk mark read
|
|
69
|
+
- `fastmail_bulk_unread` - Bulk mark unread
|
|
70
|
+
- `fastmail_bulk_flag` - Bulk flag
|
|
71
|
+
- `fastmail_bulk_unflag` - Bulk unflag
|
|
72
|
+
- `fastmail_bulk_delete` - Bulk delete
|
|
73
|
+
- `fastmail_bulk_move` - Bulk move
|
|
74
|
+
|
|
75
|
+
### Contacts (3 tools, always available)
|
|
76
|
+
|
|
77
|
+
- `fastmail_list_contacts` - List contacts
|
|
78
|
+
- `fastmail_get_contact` - Contact details
|
|
79
|
+
- `fastmail_search_contacts` - Search contacts
|
|
80
|
+
|
|
81
|
+
### Calendar (4 tools, 3 always + 1 optional)
|
|
82
|
+
|
|
83
|
+
- `fastmail_list_calendars` - List calendars
|
|
84
|
+
- `fastmail_list_events` - List events
|
|
85
|
+
- `fastmail_get_event` - Event details
|
|
86
|
+
- `fastmail_create_event` - Create event (optional)
|
|
87
|
+
|
|
88
|
+
### Memos (3 tools, 1 always + 2 optional)
|
|
89
|
+
|
|
90
|
+
- `fastmail_get_memo` - Get memo on email
|
|
91
|
+
- `fastmail_create_memo` - Add memo (optional)
|
|
92
|
+
- `fastmail_delete_memo` - Delete memo (optional)
|
|
93
|
+
|
|
94
|
+
## Architecture
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Agent -> OpenClaw Plugin -> MCP SDK (in-process) -> Remote Worker -> Fastmail JMAP API
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The plugin maintains a persistent MCP connection per workspace:
|
|
101
|
+
1. Registers OpenClaw tools with JSON Schema parameters
|
|
102
|
+
2. On first tool call, connects to the remote Worker via MCP SDK with Bearer token auth
|
|
103
|
+
3. All subsequent calls reuse the same connection (no per-call overhead)
|
|
104
|
+
4. Responses are formatted in-process using compact text formatters
|
|
105
|
+
|
|
106
|
+
One runtime dependency: `@modelcontextprotocol/sdk`.
|
|
107
|
+
|
|
108
|
+
## Development
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Clone the repo
|
|
112
|
+
git clone https://github.com/omarshahine/fastmail-mcp-remote.git
|
|
113
|
+
cd fastmail-mcp-remote/openclaw-plugin
|
|
114
|
+
|
|
115
|
+
# Install dependencies
|
|
116
|
+
npm install --legacy-peer-deps
|
|
117
|
+
|
|
118
|
+
# Type check
|
|
119
|
+
npx tsc --noEmit
|
|
120
|
+
|
|
121
|
+
# Local test (symlink into OpenClaw extensions)
|
|
122
|
+
ln -s $(pwd) ~/.openclaw/extensions/fastmail-cli
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT
|
package/index.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw plugin entry point for Fastmail.
|
|
3
|
+
*
|
|
4
|
+
* Registers 36 agent tools that proxy to the remote Fastmail MCP Worker
|
|
5
|
+
* via a persistent in-process MCP SDK connection. Responses are formatted
|
|
6
|
+
* using compact text formatters for token efficiency.
|
|
7
|
+
*
|
|
8
|
+
* Credentials (workerUrl + bearerToken) come from plugin config,
|
|
9
|
+
* supporting multi-user setups where each workspace has its own token.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { FastmailMcpClient } from "./src/mcp-client.js";
|
|
13
|
+
import { resolveCredentials } from "./src/auth.js";
|
|
14
|
+
import { registerEmailTools } from "./src/tools/email.js";
|
|
15
|
+
import { registerContactTools } from "./src/tools/contacts.js";
|
|
16
|
+
import { registerCalendarTools } from "./src/tools/calendar.js";
|
|
17
|
+
import { registerMemoTools } from "./src/tools/memo.js";
|
|
18
|
+
|
|
19
|
+
/** Minimal typed interface for the OpenClaw plugin API. */
|
|
20
|
+
export interface OpenClawApi {
|
|
21
|
+
registerTool(tool: {
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
parameters: Record<string, unknown>;
|
|
25
|
+
execute: (_id: string, params: any) => Promise<{ content: Array<{ type: string; text: string }> }>;
|
|
26
|
+
}, opts?: { optional: boolean }): void;
|
|
27
|
+
config?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type GetClientFn = () => Promise<FastmailMcpClient>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create a lazy client factory that connects on first tool call.
|
|
34
|
+
* One persistent connection per plugin instance (per workspace).
|
|
35
|
+
*/
|
|
36
|
+
function lazyClientFactory(pluginConfig: {
|
|
37
|
+
workerUrl?: string;
|
|
38
|
+
bearerToken?: string;
|
|
39
|
+
}): GetClientFn {
|
|
40
|
+
let client: FastmailMcpClient | null = null;
|
|
41
|
+
|
|
42
|
+
return async () => {
|
|
43
|
+
if (client) return client;
|
|
44
|
+
const { url, token } = resolveCredentials(pluginConfig);
|
|
45
|
+
client = new FastmailMcpClient(url, token);
|
|
46
|
+
return client;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default function register(api: OpenClawApi) {
|
|
51
|
+
const pluginConfig = (api.config || {}) as { workerUrl?: string; bearerToken?: string };
|
|
52
|
+
const getClient = lazyClientFactory(pluginConfig);
|
|
53
|
+
|
|
54
|
+
registerEmailTools(api, getClient);
|
|
55
|
+
registerContactTools(api, getClient);
|
|
56
|
+
registerCalendarTools(api, getClient);
|
|
57
|
+
registerMemoTools(api, getClient);
|
|
58
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "fastmail-cli",
|
|
3
|
+
"configSchema": {
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["workerUrl", "bearerToken"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"workerUrl": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Fastmail MCP Worker URL (e.g. https://fastmail-mcp.example.com)"
|
|
11
|
+
},
|
|
12
|
+
"bearerToken": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "Bearer token from 'fastmail auth'. Each user needs their own token."
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"uiHints": {
|
|
19
|
+
"workerUrl": {
|
|
20
|
+
"label": "Worker URL",
|
|
21
|
+
"placeholder": "https://fastmail-mcp.example.com"
|
|
22
|
+
},
|
|
23
|
+
"bearerToken": {
|
|
24
|
+
"label": "Bearer Token",
|
|
25
|
+
"placeholder": "Token from 'fastmail auth'"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"skills": [
|
|
29
|
+
"./skills"
|
|
30
|
+
]
|
|
31
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fastmail-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenClaw plugin for Fastmail email, contacts, and calendar",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"index.ts",
|
|
8
|
+
"src",
|
|
9
|
+
"skills",
|
|
10
|
+
"openclaw.plugin.json",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"openclaw",
|
|
15
|
+
"fastmail",
|
|
16
|
+
"email",
|
|
17
|
+
"mcp",
|
|
18
|
+
"agent-tools"
|
|
19
|
+
],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/omarshahine/fastmail-mcp-remote.git",
|
|
24
|
+
"directory": "openclaw-plugin"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.26.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^25.0.8",
|
|
31
|
+
"typescript": "^5.9.0"
|
|
32
|
+
},
|
|
33
|
+
"openclaw": {
|
|
34
|
+
"extensions": [
|
|
35
|
+
"./index.ts"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Fastmail Tools
|
|
2
|
+
|
|
3
|
+
Token-efficient tools for Fastmail email, contacts, and calendar. Each tool connects to a remote Fastmail MCP Worker and returns compact text optimized for LLM token efficiency (5-7x savings vs raw JSON).
|
|
4
|
+
|
|
5
|
+
## Authentication
|
|
6
|
+
|
|
7
|
+
Tools require `workerUrl` and `bearerToken` to be configured in the OpenClaw workspace. Each user needs their own token from `fastmail auth`.
|
|
8
|
+
|
|
9
|
+
## Available Tools
|
|
10
|
+
|
|
11
|
+
### Email Reading (11 tools)
|
|
12
|
+
|
|
13
|
+
| Tool | Purpose |
|
|
14
|
+
|------|---------|
|
|
15
|
+
| `fastmail_inbox` | Get recent inbox emails (IDs, dates, senders, subjects, previews) |
|
|
16
|
+
| `fastmail_get_email` | Read a single email (headers + body in markdown or HTML) |
|
|
17
|
+
| `fastmail_search_emails` | Search emails by text, with optional filters: sender, recipient, date range, unread, attachments, mailbox |
|
|
18
|
+
| `fastmail_get_thread` | Get all emails in a conversation thread |
|
|
19
|
+
| `fastmail_list_mailboxes` | List all mailboxes with IDs and email counts |
|
|
20
|
+
| `fastmail_get_mailbox_stats` | Get mailbox statistics (total, unread, threads) |
|
|
21
|
+
| `fastmail_get_account_summary` | Account overview with counts |
|
|
22
|
+
| `fastmail_list_identities` | List sending identities |
|
|
23
|
+
| `fastmail_get_attachments` | List attachments for an email |
|
|
24
|
+
| `fastmail_download_attachment` | Get download URL for an attachment |
|
|
25
|
+
| `fastmail_get_inbox_updates` | Incremental sync: get changes since a state token |
|
|
26
|
+
|
|
27
|
+
### Email Writing (3 optional tools)
|
|
28
|
+
|
|
29
|
+
| Tool | Purpose |
|
|
30
|
+
|------|---------|
|
|
31
|
+
| `fastmail_send_email` | Send an email (text, HTML, or markdown body) |
|
|
32
|
+
| `fastmail_create_draft` | Create an email draft |
|
|
33
|
+
| `fastmail_reply_to_email` | Reply to an email (reply-all, send or draft) |
|
|
34
|
+
|
|
35
|
+
### Email Organization (6 optional tools)
|
|
36
|
+
|
|
37
|
+
| Tool | Purpose |
|
|
38
|
+
|------|---------|
|
|
39
|
+
| `fastmail_mark_read` | Mark email as read |
|
|
40
|
+
| `fastmail_mark_unread` | Mark email as unread |
|
|
41
|
+
| `fastmail_flag` | Flag (star) an email |
|
|
42
|
+
| `fastmail_unflag` | Unflag (unstar) an email |
|
|
43
|
+
| `fastmail_delete` | Delete an email (move to trash) |
|
|
44
|
+
| `fastmail_move` | Move email to a different mailbox |
|
|
45
|
+
|
|
46
|
+
### Bulk Operations (6 optional tools)
|
|
47
|
+
|
|
48
|
+
| Tool | Purpose |
|
|
49
|
+
|------|---------|
|
|
50
|
+
| `fastmail_bulk_read` | Mark multiple emails as read |
|
|
51
|
+
| `fastmail_bulk_unread` | Mark multiple emails as unread |
|
|
52
|
+
| `fastmail_bulk_flag` | Flag multiple emails |
|
|
53
|
+
| `fastmail_bulk_unflag` | Unflag multiple emails |
|
|
54
|
+
| `fastmail_bulk_delete` | Delete multiple emails |
|
|
55
|
+
| `fastmail_bulk_move` | Move multiple emails to a mailbox |
|
|
56
|
+
|
|
57
|
+
### Contacts (3 tools)
|
|
58
|
+
|
|
59
|
+
| Tool | Purpose |
|
|
60
|
+
|------|---------|
|
|
61
|
+
| `fastmail_list_contacts` | List contacts with names, emails, phones |
|
|
62
|
+
| `fastmail_get_contact` | Full contact details |
|
|
63
|
+
| `fastmail_search_contacts` | Search contacts by name or email |
|
|
64
|
+
|
|
65
|
+
### Calendar (4 tools)
|
|
66
|
+
|
|
67
|
+
| Tool | Purpose |
|
|
68
|
+
|------|---------|
|
|
69
|
+
| `fastmail_list_calendars` | List calendars with IDs |
|
|
70
|
+
| `fastmail_list_events` | List events, optionally by calendar |
|
|
71
|
+
| `fastmail_get_event` | Full event details |
|
|
72
|
+
| `fastmail_create_event` | Create a calendar event (optional) |
|
|
73
|
+
|
|
74
|
+
### Memos (3 tools)
|
|
75
|
+
|
|
76
|
+
| Tool | Purpose |
|
|
77
|
+
|------|---------|
|
|
78
|
+
| `fastmail_get_memo` | Get the private memo on an email |
|
|
79
|
+
| `fastmail_create_memo` | Add a private memo to an email (optional) |
|
|
80
|
+
| `fastmail_delete_memo` | Delete a memo (optional) |
|
|
81
|
+
|
|
82
|
+
## Output Format
|
|
83
|
+
|
|
84
|
+
Tools return compact text optimized for LLM consumption. Email IDs appear first on each line for easy extraction.
|
|
85
|
+
|
|
86
|
+
### Email List Example
|
|
87
|
+
```
|
|
88
|
+
# inbox (10)
|
|
89
|
+
|
|
90
|
+
M1234abc 2026-02-19 10:30 *John Smith <john@example.com>
|
|
91
|
+
Re: Project Update -- Preview of the email content...
|
|
92
|
+
|
|
93
|
+
M5678def 2026-02-19 09:15 Jane Doe <jane@example.com> [att]
|
|
94
|
+
Contract Review -- Please review the attached...
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Indicators: `*` = unread, `!` = flagged, `[att]` = has attachments
|
|
98
|
+
|
|
99
|
+
### Single Email Example
|
|
100
|
+
```
|
|
101
|
+
From: John Smith <john@example.com>
|
|
102
|
+
To: me@example.com
|
|
103
|
+
Date: 2026-02-19 10:30
|
|
104
|
+
Subject: Re: Project Update
|
|
105
|
+
ID: M1234abc | Thread: T5678
|
|
106
|
+
|
|
107
|
+
[markdown body content]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Common Workflows
|
|
111
|
+
|
|
112
|
+
### Check inbox and read an email
|
|
113
|
+
1. `fastmail_inbox` -- see list, note IDs
|
|
114
|
+
2. `fastmail_get_email` with the ID -- read the email
|
|
115
|
+
|
|
116
|
+
### Search, read, and reply
|
|
117
|
+
1. `fastmail_search_emails` with query
|
|
118
|
+
2. `fastmail_get_email` with the ID
|
|
119
|
+
3. `fastmail_reply_to_email` with body and `send: true`
|
|
120
|
+
|
|
121
|
+
### Triage inbox
|
|
122
|
+
1. `fastmail_inbox` with limit 20
|
|
123
|
+
2. `fastmail_bulk_read` for read emails
|
|
124
|
+
3. `fastmail_delete` for unwanted emails
|
|
125
|
+
4. `fastmail_move` to archive
|
|
126
|
+
|
|
127
|
+
### Incremental sync
|
|
128
|
+
1. `fastmail_get_inbox_updates` (no state token) -- returns current state + emails
|
|
129
|
+
2. Save the `queryState` from the response
|
|
130
|
+
3. `fastmail_get_inbox_updates` with `sinceQueryState` -- only changes since last check
|
|
131
|
+
|
|
132
|
+
## Error Handling
|
|
133
|
+
|
|
134
|
+
- **"Missing workerUrl/bearerToken"** -- Configure both in your OpenClaw workspace plugin settings
|
|
135
|
+
- **"Token expired"** -- User needs to run `fastmail auth` and update the bearerToken in workspace config
|
|
136
|
+
- **Connection errors** -- Check if the MCP worker is running
|
package/src/auth.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication for the Fastmail OpenClaw plugin.
|
|
3
|
+
*
|
|
4
|
+
* Credentials (workerUrl + bearerToken) are provided via plugin config,
|
|
5
|
+
* enabling multi-user setups where each workspace has its own token.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface Credentials {
|
|
9
|
+
url: string;
|
|
10
|
+
token: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Resolve credentials from plugin config. Both fields are required.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveCredentials(pluginConfig: {
|
|
17
|
+
workerUrl?: string;
|
|
18
|
+
bearerToken?: string;
|
|
19
|
+
}): Credentials {
|
|
20
|
+
if (!pluginConfig.workerUrl) {
|
|
21
|
+
throw new Error("Missing workerUrl in plugin config");
|
|
22
|
+
}
|
|
23
|
+
if (!pluginConfig.bearerToken) {
|
|
24
|
+
throw new Error("Missing bearerToken in plugin config");
|
|
25
|
+
}
|
|
26
|
+
return { url: pluginConfig.workerUrl, token: pluginConfig.bearerToken };
|
|
27
|
+
}
|