mcpeasy 0.1.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.claudeignore +0 -3
- data/.mcp.json +19 -1
- data/CHANGELOG.md +59 -0
- data/CLAUDE.md +19 -5
- data/README.md +19 -3
- data/lib/mcpeasy/cli.rb +62 -10
- data/lib/mcpeasy/config.rb +22 -1
- data/lib/mcpeasy/setup.rb +1 -0
- data/lib/mcpeasy/version.rb +1 -1
- data/lib/utilities/gcal/README.md +11 -3
- data/lib/utilities/gcal/cli.rb +110 -108
- data/lib/utilities/gcal/mcp.rb +463 -308
- data/lib/utilities/gcal/service.rb +312 -0
- data/lib/utilities/gdrive/README.md +3 -3
- data/lib/utilities/gdrive/cli.rb +98 -96
- data/lib/utilities/gdrive/mcp.rb +290 -288
- data/lib/utilities/gdrive/service.rb +293 -0
- data/lib/utilities/gmail/README.md +278 -0
- data/lib/utilities/gmail/cli.rb +264 -0
- data/lib/utilities/gmail/mcp.rb +846 -0
- data/lib/utilities/gmail/service.rb +547 -0
- data/lib/utilities/gmeet/cli.rb +131 -129
- data/lib/utilities/gmeet/mcp.rb +374 -372
- data/lib/utilities/gmeet/service.rb +411 -0
- data/lib/utilities/notion/README.md +287 -0
- data/lib/utilities/notion/cli.rb +245 -0
- data/lib/utilities/notion/mcp.rb +607 -0
- data/lib/utilities/notion/service.rb +327 -0
- data/lib/utilities/slack/README.md +3 -3
- data/lib/utilities/slack/cli.rb +69 -54
- data/lib/utilities/slack/mcp.rb +277 -226
- data/lib/utilities/slack/service.rb +134 -0
- data/mcpeasy.gemspec +6 -1
- metadata +87 -10
- data/env.template +0 -11
- data/lib/utilities/gcal/gcal_tool.rb +0 -308
- data/lib/utilities/gdrive/gdrive_tool.rb +0 -291
- data/lib/utilities/gmeet/gmeet_tool.rb +0 -407
- data/lib/utilities/slack/slack_tool.rb +0 -119
- data/logs/.keep +0 -0
@@ -0,0 +1,293 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "google/apis/drive_v3"
|
5
|
+
require "googleauth"
|
6
|
+
require "signet/oauth_2/client"
|
7
|
+
require "fileutils"
|
8
|
+
require "json"
|
9
|
+
require "time"
|
10
|
+
require_relative "../_google/auth_server"
|
11
|
+
require_relative "../../mcpeasy/config"
|
12
|
+
|
13
|
+
module Gdrive
|
14
|
+
class Service
|
15
|
+
SCOPES = [
|
16
|
+
"https://www.googleapis.com/auth/calendar.readonly",
|
17
|
+
"https://www.googleapis.com/auth/drive.readonly"
|
18
|
+
]
|
19
|
+
SCOPE = SCOPES.join(" ")
|
20
|
+
|
21
|
+
# MIME type mappings for Google Workspace documents
|
22
|
+
EXPORT_FORMATS = {
|
23
|
+
"application/vnd.google-apps.document" => {
|
24
|
+
format: "text/markdown",
|
25
|
+
extension: ".md"
|
26
|
+
},
|
27
|
+
"application/vnd.google-apps.spreadsheet" => {
|
28
|
+
format: "text/csv",
|
29
|
+
extension: ".csv"
|
30
|
+
},
|
31
|
+
"application/vnd.google-apps.presentation" => {
|
32
|
+
format: "text/plain",
|
33
|
+
extension: ".txt"
|
34
|
+
},
|
35
|
+
"application/vnd.google-apps.drawing" => {
|
36
|
+
format: "image/png",
|
37
|
+
extension: ".png"
|
38
|
+
}
|
39
|
+
}.freeze
|
40
|
+
|
41
|
+
def initialize(skip_auth: false)
|
42
|
+
ensure_env!
|
43
|
+
@service = Google::Apis::DriveV3::DriveService.new
|
44
|
+
@service.authorization = authorize unless skip_auth
|
45
|
+
end
|
46
|
+
|
47
|
+
def search_files(query, max_results: 10)
|
48
|
+
results = @service.list_files(
|
49
|
+
q: "fullText contains '#{query.gsub("'", "\\'")}' and trashed=false",
|
50
|
+
page_size: max_results,
|
51
|
+
fields: "files(id,name,mimeType,size,modifiedTime,webViewLink)"
|
52
|
+
)
|
53
|
+
|
54
|
+
files = results.files.map do |file|
|
55
|
+
{
|
56
|
+
id: file.id,
|
57
|
+
name: file.name,
|
58
|
+
mime_type: file.mime_type,
|
59
|
+
size: file.size&.to_i,
|
60
|
+
modified_time: file.modified_time,
|
61
|
+
web_view_link: file.web_view_link
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
{files: files, count: files.length}
|
66
|
+
rescue Google::Apis::Error => e
|
67
|
+
raise "Google Drive API Error: #{e.message}"
|
68
|
+
rescue => e
|
69
|
+
log_error("search_files", e)
|
70
|
+
raise e
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_file_content(file_id)
|
74
|
+
# First get file metadata
|
75
|
+
file = @service.get_file(file_id, fields: "id,name,mimeType,size")
|
76
|
+
|
77
|
+
content = if EXPORT_FORMATS.key?(file.mime_type)
|
78
|
+
# Export Google Workspace document
|
79
|
+
export_format = EXPORT_FORMATS[file.mime_type][:format]
|
80
|
+
@service.export_file(file_id, export_format)
|
81
|
+
else
|
82
|
+
# Download regular file
|
83
|
+
@service.get_file(file_id, download_dest: StringIO.new)
|
84
|
+
end
|
85
|
+
|
86
|
+
{
|
87
|
+
id: file.id,
|
88
|
+
name: file.name,
|
89
|
+
mime_type: file.mime_type,
|
90
|
+
size: file.size&.to_i,
|
91
|
+
content: content.is_a?(StringIO) ? content.string : content
|
92
|
+
}
|
93
|
+
rescue Google::Apis::Error => e
|
94
|
+
raise "Google Drive API Error: #{e.message}"
|
95
|
+
rescue => e
|
96
|
+
log_error("get_file_content", e)
|
97
|
+
raise e
|
98
|
+
end
|
99
|
+
|
100
|
+
def list_files(max_results: 20)
|
101
|
+
results = @service.list_files(
|
102
|
+
q: "trashed=false",
|
103
|
+
page_size: max_results,
|
104
|
+
order_by: "modifiedTime desc",
|
105
|
+
fields: "files(id,name,mimeType,size,modifiedTime,webViewLink)"
|
106
|
+
)
|
107
|
+
|
108
|
+
files = results.files.map do |file|
|
109
|
+
{
|
110
|
+
id: file.id,
|
111
|
+
name: file.name,
|
112
|
+
mime_type: file.mime_type,
|
113
|
+
size: file.size&.to_i,
|
114
|
+
modified_time: file.modified_time,
|
115
|
+
web_view_link: file.web_view_link
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
{files: files, count: files.length}
|
120
|
+
rescue Google::Apis::Error => e
|
121
|
+
raise "Google Drive API Error: #{e.message}"
|
122
|
+
rescue => e
|
123
|
+
log_error("list_files", e)
|
124
|
+
raise e
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_connection
|
128
|
+
about = @service.get_about(fields: "user,storageQuota")
|
129
|
+
{
|
130
|
+
ok: true,
|
131
|
+
user: about.user.display_name,
|
132
|
+
email: about.user.email_address,
|
133
|
+
storage_used: about.storage_quota&.usage,
|
134
|
+
storage_limit: about.storage_quota&.limit
|
135
|
+
}
|
136
|
+
rescue Google::Apis::Error => e
|
137
|
+
raise "Google Drive API Error: #{e.message}"
|
138
|
+
rescue => e
|
139
|
+
log_error("test_connection", e)
|
140
|
+
raise e
|
141
|
+
end
|
142
|
+
|
143
|
+
def authenticate
|
144
|
+
perform_auth_flow
|
145
|
+
{success: true}
|
146
|
+
rescue => e
|
147
|
+
{success: false, error: e.message}
|
148
|
+
end
|
149
|
+
|
150
|
+
def perform_auth_flow
|
151
|
+
client_id = Mcpeasy::Config.google_client_id
|
152
|
+
client_secret = Mcpeasy::Config.google_client_secret
|
153
|
+
|
154
|
+
unless client_id && client_secret
|
155
|
+
raise "Google credentials not found. Please save your credentials.json file using: mcpz config set_google_credentials <path_to_credentials.json>"
|
156
|
+
end
|
157
|
+
|
158
|
+
# Create credentials using OAuth2 flow with localhost redirect
|
159
|
+
redirect_uri = "http://localhost:8080"
|
160
|
+
client = Signet::OAuth2::Client.new(
|
161
|
+
client_id: client_id,
|
162
|
+
client_secret: client_secret,
|
163
|
+
scope: SCOPE,
|
164
|
+
redirect_uri: redirect_uri,
|
165
|
+
authorization_uri: "https://accounts.google.com/o/oauth2/auth",
|
166
|
+
token_credential_uri: "https://oauth2.googleapis.com/token"
|
167
|
+
)
|
168
|
+
|
169
|
+
# Generate authorization URL
|
170
|
+
url = client.authorization_uri.to_s
|
171
|
+
|
172
|
+
puts "DEBUG: Client ID: #{client_id[0..20]}..."
|
173
|
+
puts "DEBUG: Scope: #{SCOPE}"
|
174
|
+
puts "DEBUG: Redirect URI: #{redirect_uri}"
|
175
|
+
puts
|
176
|
+
|
177
|
+
# Start callback server to capture OAuth code
|
178
|
+
puts "Starting temporary web server to capture OAuth callback..."
|
179
|
+
puts "Opening authorization URL in your default browser..."
|
180
|
+
puts url
|
181
|
+
puts
|
182
|
+
|
183
|
+
# Automatically open URL in default browser on macOS/Unix
|
184
|
+
if system("which open > /dev/null 2>&1")
|
185
|
+
system("open", url)
|
186
|
+
else
|
187
|
+
puts "Could not automatically open browser. Please copy the URL above manually."
|
188
|
+
end
|
189
|
+
puts
|
190
|
+
puts "Waiting for OAuth callback... (will timeout in 60 seconds)"
|
191
|
+
|
192
|
+
# Wait for the authorization code with timeout
|
193
|
+
code = GoogleAuthServer.capture_auth_code
|
194
|
+
|
195
|
+
unless code
|
196
|
+
raise "Failed to receive authorization code. Please try again."
|
197
|
+
end
|
198
|
+
|
199
|
+
puts "✅ Authorization code received!"
|
200
|
+
client.code = code
|
201
|
+
client.fetch_access_token!
|
202
|
+
|
203
|
+
# Save credentials to config
|
204
|
+
credentials_data = {
|
205
|
+
client_id: client.client_id,
|
206
|
+
client_secret: client.client_secret,
|
207
|
+
scope: client.scope,
|
208
|
+
refresh_token: client.refresh_token,
|
209
|
+
access_token: client.access_token,
|
210
|
+
expires_at: client.expires_at
|
211
|
+
}
|
212
|
+
|
213
|
+
Mcpeasy::Config.save_google_token(credentials_data)
|
214
|
+
puts "✅ Authentication successful! Token saved to config"
|
215
|
+
|
216
|
+
client
|
217
|
+
rescue => e
|
218
|
+
log_error("perform_auth_flow", e)
|
219
|
+
raise "Authentication flow failed: #{e.message}"
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
def authorize
|
225
|
+
credentials_data = Mcpeasy::Config.google_token
|
226
|
+
unless credentials_data
|
227
|
+
raise <<~ERROR
|
228
|
+
Google Drive authentication required!
|
229
|
+
Run the auth command first:
|
230
|
+
mcpz gdrive auth
|
231
|
+
ERROR
|
232
|
+
end
|
233
|
+
|
234
|
+
client = Signet::OAuth2::Client.new(
|
235
|
+
client_id: credentials_data.client_id,
|
236
|
+
client_secret: credentials_data.client_secret,
|
237
|
+
scope: credentials_data.scope.respond_to?(:to_a) ? credentials_data.scope.to_a.join(" ") : credentials_data.scope.to_s,
|
238
|
+
refresh_token: credentials_data.refresh_token,
|
239
|
+
access_token: credentials_data.access_token,
|
240
|
+
token_credential_uri: "https://oauth2.googleapis.com/token"
|
241
|
+
)
|
242
|
+
|
243
|
+
# Check if token needs refresh
|
244
|
+
if credentials_data.expires_at
|
245
|
+
expires_at = if credentials_data.expires_at.is_a?(String)
|
246
|
+
Time.parse(credentials_data.expires_at)
|
247
|
+
else
|
248
|
+
Time.at(credentials_data.expires_at)
|
249
|
+
end
|
250
|
+
|
251
|
+
if Time.now >= expires_at
|
252
|
+
client.refresh!
|
253
|
+
# Update saved credentials with new access token
|
254
|
+
updated_data = {
|
255
|
+
client_id: credentials_data.client_id,
|
256
|
+
client_secret: credentials_data.client_secret,
|
257
|
+
scope: credentials_data.scope.respond_to?(:to_a) ? credentials_data.scope.to_a.join(" ") : credentials_data.scope.to_s,
|
258
|
+
refresh_token: credentials_data.refresh_token,
|
259
|
+
access_token: client.access_token,
|
260
|
+
expires_at: client.expires_at
|
261
|
+
}
|
262
|
+
Mcpeasy::Config.save_google_token(updated_data)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
client
|
267
|
+
rescue JSON::ParserError
|
268
|
+
raise "Invalid token data. Please re-run: mcpz gdrive auth"
|
269
|
+
rescue => e
|
270
|
+
log_error("authorize", e)
|
271
|
+
raise "Authentication failed: #{e.message}"
|
272
|
+
end
|
273
|
+
|
274
|
+
def ensure_env!
|
275
|
+
unless Mcpeasy::Config.google_client_id && Mcpeasy::Config.google_client_secret
|
276
|
+
raise <<~ERROR
|
277
|
+
Google API credentials not configured!
|
278
|
+
Please save your Google credentials.json file using:
|
279
|
+
mcpz config set_google_credentials <path_to_credentials.json>
|
280
|
+
ERROR
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def log_error(method, error)
|
285
|
+
Mcpeasy::Config.ensure_config_dirs
|
286
|
+
File.write(
|
287
|
+
Mcpeasy::Config.log_file_path("gdrive", "error"),
|
288
|
+
"#{Time.now}: #{method} error: #{error.class}: #{error.message}\n#{error.backtrace.join("\n")}\n",
|
289
|
+
mode: "a"
|
290
|
+
)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
# Gmail MCP Server
|
2
|
+
|
3
|
+
A Model Context Protocol (MCP) server for Gmail integration with AI assistants.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- **List emails** with filtering by date range, sender, subject, labels, and read/unread status
|
8
|
+
- **Search emails** using Gmail's powerful search syntax
|
9
|
+
- **Get email content** including full body, headers, and attachment information
|
10
|
+
- **Send emails** with support for CC, BCC, and reply-to fields
|
11
|
+
- **Reply to emails** with automatic threading and optional quoted text
|
12
|
+
- **Email management** - mark as read/unread, add/remove labels, archive, and trash
|
13
|
+
- **Test connection** to verify Gmail API connectivity
|
14
|
+
|
15
|
+
## Prerequisites
|
16
|
+
|
17
|
+
1. **Google Cloud Project** with Gmail API enabled
|
18
|
+
2. **OAuth 2.0 credentials** (client ID and client secret)
|
19
|
+
3. **Ruby environment** with required gems
|
20
|
+
|
21
|
+
## Setup
|
22
|
+
|
23
|
+
### 1. Enable Gmail API
|
24
|
+
|
25
|
+
1. Go to the [Google Cloud Console](https://console.cloud.google.com)
|
26
|
+
2. Create a new project or select an existing one
|
27
|
+
3. Enable the Gmail API:
|
28
|
+
- Navigate to "APIs & Services" > "Library"
|
29
|
+
- Search for "Gmail API" and click "Enable"
|
30
|
+
|
31
|
+
### 2. Create OAuth 2.0 Credentials
|
32
|
+
|
33
|
+
1. Go to "APIs & Services" > "Credentials"
|
34
|
+
2. Click "Create Credentials" > "OAuth 2.0 Client IDs"
|
35
|
+
3. Set application type to "Desktop application"
|
36
|
+
4. Download the JSON file containing your credentials
|
37
|
+
|
38
|
+
### 3. Install and Configure MCPEasy
|
39
|
+
|
40
|
+
```bash
|
41
|
+
# Install the gem
|
42
|
+
gem install mcpeasy
|
43
|
+
|
44
|
+
# Set up configuration directories
|
45
|
+
mcpz setup
|
46
|
+
|
47
|
+
# Save your Google credentials
|
48
|
+
mcpz set_google_credentials path/to/your/credentials.json
|
49
|
+
|
50
|
+
# Authenticate with Gmail (will open browser for OAuth)
|
51
|
+
mcpz gmail auth
|
52
|
+
```
|
53
|
+
|
54
|
+
### 4. Verify Setup
|
55
|
+
|
56
|
+
```bash
|
57
|
+
# Test the connection
|
58
|
+
mcpz gmail test
|
59
|
+
```
|
60
|
+
|
61
|
+
## CLI Usage
|
62
|
+
|
63
|
+
### Authentication
|
64
|
+
```bash
|
65
|
+
# Authenticate with Gmail API
|
66
|
+
mcpz gmail auth
|
67
|
+
```
|
68
|
+
|
69
|
+
### Listing Emails
|
70
|
+
```bash
|
71
|
+
# List recent emails
|
72
|
+
mcpz gmail list
|
73
|
+
|
74
|
+
# Filter by date range
|
75
|
+
mcpz gmail list --start_date 2024-01-01 --end_date 2024-01-31
|
76
|
+
|
77
|
+
# Filter by sender
|
78
|
+
mcpz gmail list --sender "someone@example.com"
|
79
|
+
|
80
|
+
# Filter by subject
|
81
|
+
mcpz gmail list --subject "Important"
|
82
|
+
|
83
|
+
# Filter by labels
|
84
|
+
mcpz gmail list --labels "inbox,important"
|
85
|
+
|
86
|
+
# Filter by read status
|
87
|
+
mcpz gmail list --read_status unread
|
88
|
+
|
89
|
+
# Limit results
|
90
|
+
mcpz gmail list --max_results 10
|
91
|
+
```
|
92
|
+
|
93
|
+
### Searching Emails
|
94
|
+
```bash
|
95
|
+
# Basic search
|
96
|
+
mcpz gmail search "quarterly report"
|
97
|
+
|
98
|
+
# Advanced Gmail search syntax
|
99
|
+
mcpz gmail search "from:boss@company.com subject:urgent"
|
100
|
+
mcpz gmail search "has:attachment filename:pdf"
|
101
|
+
mcpz gmail search "is:unread after:2024/01/01"
|
102
|
+
```
|
103
|
+
|
104
|
+
### Reading Emails
|
105
|
+
```bash
|
106
|
+
# Read a specific email by ID
|
107
|
+
mcpz gmail read 18c8b5d4e8f9a2b6
|
108
|
+
```
|
109
|
+
|
110
|
+
### Sending Emails
|
111
|
+
```bash
|
112
|
+
# Send a basic email
|
113
|
+
mcpz gmail send \
|
114
|
+
--to "recipient@example.com" \
|
115
|
+
--subject "Hello from MCPEasy" \
|
116
|
+
--body "This is a test email sent via Gmail API."
|
117
|
+
|
118
|
+
# Send with CC and BCC
|
119
|
+
mcpz gmail send \
|
120
|
+
--to "recipient@example.com" \
|
121
|
+
--cc "cc@example.com" \
|
122
|
+
--bcc "bcc@example.com" \
|
123
|
+
--subject "Team Update" \
|
124
|
+
--body "Weekly team update..." \
|
125
|
+
--reply_to "noreply@example.com"
|
126
|
+
```
|
127
|
+
|
128
|
+
### Replying to Emails
|
129
|
+
```bash
|
130
|
+
# Reply to an email
|
131
|
+
mcpz gmail reply 18c8b5d4e8f9a2b6 \
|
132
|
+
--body "Thank you for your message."
|
133
|
+
|
134
|
+
# Reply without including quoted original message
|
135
|
+
mcpz gmail reply 18c8b5d4e8f9a2b6 \
|
136
|
+
--body "Thank you for your message." \
|
137
|
+
--include_quoted false
|
138
|
+
```
|
139
|
+
|
140
|
+
### Email Management
|
141
|
+
```bash
|
142
|
+
# Mark as read/unread
|
143
|
+
mcpz gmail mark_read 18c8b5d4e8f9a2b6
|
144
|
+
mcpz gmail mark_unread 18c8b5d4e8f9a2b6
|
145
|
+
|
146
|
+
# Add/remove labels
|
147
|
+
mcpz gmail add_label 18c8b5d4e8f9a2b6 "important"
|
148
|
+
mcpz gmail remove_label 18c8b5d4e8f9a2b6 "important"
|
149
|
+
|
150
|
+
# Archive email (remove from inbox)
|
151
|
+
mcpz gmail archive 18c8b5d4e8f9a2b6
|
152
|
+
|
153
|
+
# Move to trash
|
154
|
+
mcpz gmail trash 18c8b5d4e8f9a2b6
|
155
|
+
```
|
156
|
+
|
157
|
+
## MCP Server Usage
|
158
|
+
|
159
|
+
### Running the Server
|
160
|
+
|
161
|
+
```bash
|
162
|
+
# Start the Gmail MCP server
|
163
|
+
mcpz gmail mcp
|
164
|
+
```
|
165
|
+
|
166
|
+
### MCP Configuration
|
167
|
+
|
168
|
+
Add to your `.mcp.json` configuration:
|
169
|
+
|
170
|
+
```json
|
171
|
+
{
|
172
|
+
"mcpServers": {
|
173
|
+
"gmail": {
|
174
|
+
"command": "mcpz",
|
175
|
+
"args": ["gmail", "mcp"]
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
```
|
180
|
+
|
181
|
+
### Available MCP Tools
|
182
|
+
|
183
|
+
- `test_connection` - Test Gmail API connectivity
|
184
|
+
- `list_emails` - List emails with filtering options
|
185
|
+
- `search_emails` - Search emails using Gmail syntax
|
186
|
+
- `get_email_content` - Get full email content including attachments
|
187
|
+
- `send_email` - Send new emails
|
188
|
+
- `reply_to_email` - Reply to existing emails
|
189
|
+
- `mark_as_read` / `mark_as_unread` - Change read status
|
190
|
+
- `add_label` / `remove_label` - Manage email labels
|
191
|
+
- `archive_email` - Archive emails
|
192
|
+
- `trash_email` - Move emails to trash
|
193
|
+
|
194
|
+
### Available MCP Prompts
|
195
|
+
|
196
|
+
- `check_email` - Check inbox for new messages
|
197
|
+
- `compose_email` - Compose and send emails
|
198
|
+
- `email_search` - Search through emails
|
199
|
+
- `email_management` - Manage emails (read/unread, archive, etc.)
|
200
|
+
|
201
|
+
## Gmail Search Syntax
|
202
|
+
|
203
|
+
The Gmail MCP server supports Gmail's advanced search operators:
|
204
|
+
|
205
|
+
- `from:sender@example.com` - From specific sender
|
206
|
+
- `to:recipient@example.com` - To specific recipient
|
207
|
+
- `subject:keyword` - Subject contains keyword
|
208
|
+
- `has:attachment` - Has attachments
|
209
|
+
- `filename:pdf` - Attachment filename contains "pdf"
|
210
|
+
- `is:unread` / `is:read` - Read status
|
211
|
+
- `is:important` / `is:starred` - Importance/starred
|
212
|
+
- `label:labelname` - Has specific label
|
213
|
+
- `after:2024/01/01` / `before:2024/12/31` - Date ranges
|
214
|
+
- `newer_than:7d` / `older_than:1m` - Relative dates
|
215
|
+
|
216
|
+
## API Scopes
|
217
|
+
|
218
|
+
This MCP server requires the following Gmail API scopes:
|
219
|
+
|
220
|
+
- `https://www.googleapis.com/auth/gmail.readonly` - Read access to Gmail
|
221
|
+
- `https://www.googleapis.com/auth/gmail.send` - Send emails
|
222
|
+
- `https://www.googleapis.com/auth/gmail.modify` - Modify email labels and status
|
223
|
+
|
224
|
+
## Security Notes
|
225
|
+
|
226
|
+
- **OAuth tokens are stored locally** in `~/.config/mcpeasy/`
|
227
|
+
- **Tokens are automatically refreshed** when they expire
|
228
|
+
- **Only your authenticated user** can access emails through this server
|
229
|
+
- **No emails are stored** by the MCP server - all data comes directly from Gmail
|
230
|
+
|
231
|
+
## Troubleshooting
|
232
|
+
|
233
|
+
### Authentication Issues
|
234
|
+
|
235
|
+
```bash
|
236
|
+
# Re-authenticate if you see authentication errors
|
237
|
+
mcpz gmail auth
|
238
|
+
|
239
|
+
# Check configuration status
|
240
|
+
mcpz config
|
241
|
+
```
|
242
|
+
|
243
|
+
### API Quota Errors
|
244
|
+
|
245
|
+
Gmail API has usage quotas. If you hit rate limits:
|
246
|
+
- Reduce the number of requests
|
247
|
+
- Add delays between operations
|
248
|
+
- Check your Google Cloud Console quota usage
|
249
|
+
|
250
|
+
### Common Error Messages
|
251
|
+
|
252
|
+
- **"Gmail authentication required"** - Run `mcpz gmail auth`
|
253
|
+
- **"Google API credentials not configured"** - Run `mcpz set_google_credentials <path>`
|
254
|
+
- **"Gmail API Error: Insufficient Permission"** - Re-run authentication to grant necessary scopes
|
255
|
+
|
256
|
+
## Development
|
257
|
+
|
258
|
+
The Gmail MCP server follows the same patterns as other MCPEasy services:
|
259
|
+
|
260
|
+
- `service.rb` - Core Gmail API functionality
|
261
|
+
- `cli.rb` - Thor-based CLI commands
|
262
|
+
- `mcp.rb` - MCP server implementation
|
263
|
+
- `README.md` - Documentation
|
264
|
+
|
265
|
+
For development setup:
|
266
|
+
|
267
|
+
```bash
|
268
|
+
# Clone the repository
|
269
|
+
git clone https://github.com/your-repo/mcpeasy.git
|
270
|
+
cd mcpeasy
|
271
|
+
|
272
|
+
# Install dependencies
|
273
|
+
bundle install
|
274
|
+
|
275
|
+
# Build and install locally
|
276
|
+
gem build mcpeasy.gemspec
|
277
|
+
gem install mcpeasy-*.gem
|
278
|
+
```
|