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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.claudeignore +0 -3
  3. data/.mcp.json +19 -1
  4. data/CHANGELOG.md +59 -0
  5. data/CLAUDE.md +19 -5
  6. data/README.md +19 -3
  7. data/lib/mcpeasy/cli.rb +62 -10
  8. data/lib/mcpeasy/config.rb +22 -1
  9. data/lib/mcpeasy/setup.rb +1 -0
  10. data/lib/mcpeasy/version.rb +1 -1
  11. data/lib/utilities/gcal/README.md +11 -3
  12. data/lib/utilities/gcal/cli.rb +110 -108
  13. data/lib/utilities/gcal/mcp.rb +463 -308
  14. data/lib/utilities/gcal/service.rb +312 -0
  15. data/lib/utilities/gdrive/README.md +3 -3
  16. data/lib/utilities/gdrive/cli.rb +98 -96
  17. data/lib/utilities/gdrive/mcp.rb +290 -288
  18. data/lib/utilities/gdrive/service.rb +293 -0
  19. data/lib/utilities/gmail/README.md +278 -0
  20. data/lib/utilities/gmail/cli.rb +264 -0
  21. data/lib/utilities/gmail/mcp.rb +846 -0
  22. data/lib/utilities/gmail/service.rb +547 -0
  23. data/lib/utilities/gmeet/cli.rb +131 -129
  24. data/lib/utilities/gmeet/mcp.rb +374 -372
  25. data/lib/utilities/gmeet/service.rb +411 -0
  26. data/lib/utilities/notion/README.md +287 -0
  27. data/lib/utilities/notion/cli.rb +245 -0
  28. data/lib/utilities/notion/mcp.rb +607 -0
  29. data/lib/utilities/notion/service.rb +327 -0
  30. data/lib/utilities/slack/README.md +3 -3
  31. data/lib/utilities/slack/cli.rb +69 -54
  32. data/lib/utilities/slack/mcp.rb +277 -226
  33. data/lib/utilities/slack/service.rb +134 -0
  34. data/mcpeasy.gemspec +6 -1
  35. metadata +87 -10
  36. data/env.template +0 -11
  37. data/lib/utilities/gcal/gcal_tool.rb +0 -308
  38. data/lib/utilities/gdrive/gdrive_tool.rb +0 -291
  39. data/lib/utilities/gmeet/gmeet_tool.rb +0 -407
  40. data/lib/utilities/slack/slack_tool.rb +0 -119
  41. data/logs/.keep +0 -0
@@ -0,0 +1,264 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "thor"
5
+ require_relative "service"
6
+
7
+ module Gmail
8
+ class CLI < Thor
9
+ desc "test", "Test the Gmail API connection"
10
+ def test
11
+ response = tool.test_connection
12
+
13
+ if response[:ok]
14
+ puts "✅ Successfully connected to Gmail"
15
+ puts " Email: #{response[:email]}"
16
+ puts " Messages: #{response[:messages_total]}"
17
+ puts " Threads: #{response[:threads_total]}"
18
+ else
19
+ warn "❌ Connection test failed"
20
+ end
21
+ rescue RuntimeError => e
22
+ puts "❌ Failed to connect to Gmail: #{e.message}\n\n#{e.backtrace.join("\n")}"
23
+ exit 1
24
+ end
25
+
26
+ desc "list", "List recent emails"
27
+ method_option :start_date, type: :string, aliases: "-s", desc: "Start date (YYYY-MM-DD)"
28
+ method_option :end_date, type: :string, aliases: "-e", desc: "End date (YYYY-MM-DD)"
29
+ method_option :max_results, type: :numeric, default: 20, aliases: "-n", desc: "Max number of emails"
30
+ method_option :sender, type: :string, aliases: "-f", desc: "Filter by sender email"
31
+ method_option :subject, type: :string, aliases: "-j", desc: "Filter by subject"
32
+ method_option :labels, type: :string, aliases: "-l", desc: "Filter by labels (comma-separated)"
33
+ method_option :read_status, type: :string, aliases: "-r", desc: "Filter by read status (read/unread)"
34
+ def list
35
+ labels = options[:labels]&.split(",")&.map(&:strip)
36
+
37
+ result = tool.list_emails(
38
+ start_date: options[:start_date],
39
+ end_date: options[:end_date],
40
+ max_results: options[:max_results],
41
+ sender: options[:sender],
42
+ subject: options[:subject],
43
+ labels: labels,
44
+ read_status: options[:read_status]
45
+ )
46
+ emails = result[:emails]
47
+
48
+ if emails.empty?
49
+ puts "📧 No emails found for the specified criteria"
50
+ else
51
+ puts "📧 Found #{result[:count]} email(s):"
52
+ emails.each_with_index do |email, index|
53
+ puts " #{index + 1}. #{email[:subject] || "No subject"}"
54
+ puts " From: #{email[:from]}"
55
+ puts " Date: #{email[:date]}"
56
+ puts " Snippet: #{email[:snippet]}" if email[:snippet]
57
+ puts " Labels: #{email[:labels].join(", ")}" if email[:labels]&.any?
58
+ puts " ID: #{email[:id]}"
59
+ puts
60
+ end
61
+ end
62
+ rescue RuntimeError => e
63
+ warn "❌ Failed to list emails: #{e.message}"
64
+ exit 1
65
+ end
66
+
67
+ desc "search QUERY", "Search emails by text content"
68
+ method_option :max_results, type: :numeric, default: 10, aliases: "-n", desc: "Max number of emails"
69
+ def search(query)
70
+ result = tool.search_emails(
71
+ query,
72
+ max_results: options[:max_results]
73
+ )
74
+ emails = result[:emails]
75
+
76
+ if emails.empty?
77
+ puts "🔍 No emails found matching '#{query}'"
78
+ else
79
+ puts "🔍 Found #{result[:count]} email(s) matching '#{query}':"
80
+ emails.each_with_index do |email, index|
81
+ puts " #{index + 1}. #{email[:subject] || "No subject"}"
82
+ puts " From: #{email[:from]}"
83
+ puts " Date: #{email[:date]}"
84
+ puts " Snippet: #{email[:snippet]}" if email[:snippet]
85
+ puts " ID: #{email[:id]}"
86
+ puts
87
+ end
88
+ end
89
+ rescue RuntimeError => e
90
+ warn "❌ Failed to search emails: #{e.message}"
91
+ exit 1
92
+ end
93
+
94
+ desc "read EMAIL_ID", "Read a specific email"
95
+ def read(email_id)
96
+ email = tool.get_email_content(email_id)
97
+
98
+ puts "📧 Email Details:"
99
+ puts " ID: #{email[:id]}"
100
+ puts " Thread ID: #{email[:thread_id]}"
101
+ puts " Subject: #{email[:subject] || "No subject"}"
102
+ puts " From: #{email[:from]}"
103
+ puts " To: #{email[:to]}"
104
+ puts " CC: #{email[:cc]}" if email[:cc]
105
+ puts " BCC: #{email[:bcc]}" if email[:bcc]
106
+ puts " Date: #{email[:date]}"
107
+ puts " Labels: #{email[:labels].join(", ")}" if email[:labels]&.any?
108
+
109
+ if email[:attachments]&.any?
110
+ puts " Attachments:"
111
+ email[:attachments].each do |attachment|
112
+ puts " - #{attachment[:filename]} (#{attachment[:mime_type]}, #{attachment[:size]} bytes)"
113
+ end
114
+ end
115
+
116
+ puts "\n📄 Body:"
117
+ puts email[:body]
118
+ rescue RuntimeError => e
119
+ warn "❌ Failed to read email: #{e.message}"
120
+ exit 1
121
+ end
122
+
123
+ desc "send", "Send a new email"
124
+ method_option :to, type: :string, required: true, aliases: "-t", desc: "Recipient email address"
125
+ method_option :subject, type: :string, required: true, aliases: "-s", desc: "Email subject"
126
+ method_option :body, type: :string, required: true, aliases: "-b", desc: "Email body"
127
+ method_option :cc, type: :string, aliases: "-c", desc: "CC email address"
128
+ method_option :bcc, type: :string, aliases: "-B", desc: "BCC email address"
129
+ method_option :reply_to, type: :string, aliases: "-r", desc: "Reply-to email address"
130
+ def send
131
+ result = tool.send_email(
132
+ to: options[:to],
133
+ subject: options[:subject],
134
+ body: options[:body],
135
+ cc: options[:cc],
136
+ bcc: options[:bcc],
137
+ reply_to: options[:reply_to]
138
+ )
139
+
140
+ if result[:success]
141
+ puts "✅ Email sent successfully"
142
+ puts " Message ID: #{result[:message_id]}"
143
+ puts " Thread ID: #{result[:thread_id]}"
144
+ else
145
+ puts "❌ Failed to send email"
146
+ end
147
+ rescue RuntimeError => e
148
+ warn "❌ Failed to send email: #{e.message}"
149
+ exit 1
150
+ end
151
+
152
+ desc "reply EMAIL_ID", "Reply to an email"
153
+ method_option :body, type: :string, required: true, aliases: "-b", desc: "Reply body"
154
+ method_option :include_quoted, type: :boolean, default: true, aliases: "-q", desc: "Include quoted original message"
155
+ def reply(email_id)
156
+ result = tool.reply_to_email(
157
+ email_id: email_id,
158
+ body: options[:body],
159
+ include_quoted: options[:include_quoted]
160
+ )
161
+
162
+ if result[:success]
163
+ puts "✅ Reply sent successfully"
164
+ puts " Message ID: #{result[:message_id]}"
165
+ puts " Thread ID: #{result[:thread_id]}"
166
+ else
167
+ puts "❌ Failed to send reply"
168
+ end
169
+ rescue RuntimeError => e
170
+ warn "❌ Failed to send reply: #{e.message}"
171
+ exit 1
172
+ end
173
+
174
+ desc "mark_read EMAIL_ID", "Mark an email as read"
175
+ def mark_read(email_id)
176
+ result = tool.mark_as_read(email_id)
177
+
178
+ if result[:success]
179
+ puts "✅ Email marked as read"
180
+ else
181
+ puts "❌ Failed to mark email as read"
182
+ end
183
+ rescue RuntimeError => e
184
+ warn "❌ Failed to mark email as read: #{e.message}"
185
+ exit 1
186
+ end
187
+
188
+ desc "mark_unread EMAIL_ID", "Mark an email as unread"
189
+ def mark_unread(email_id)
190
+ result = tool.mark_as_unread(email_id)
191
+
192
+ if result[:success]
193
+ puts "✅ Email marked as unread"
194
+ else
195
+ puts "❌ Failed to mark email as unread"
196
+ end
197
+ rescue RuntimeError => e
198
+ warn "❌ Failed to mark email as unread: #{e.message}"
199
+ exit 1
200
+ end
201
+
202
+ desc "add_label EMAIL_ID LABEL", "Add a label to an email"
203
+ def add_label(email_id, label)
204
+ result = tool.add_label(email_id, label)
205
+
206
+ if result[:success]
207
+ puts "✅ Label '#{label}' added to email"
208
+ else
209
+ puts "❌ Failed to add label to email"
210
+ end
211
+ rescue RuntimeError => e
212
+ warn "❌ Failed to add label to email: #{e.message}"
213
+ exit 1
214
+ end
215
+
216
+ desc "remove_label EMAIL_ID LABEL", "Remove a label from an email"
217
+ def remove_label(email_id, label)
218
+ result = tool.remove_label(email_id, label)
219
+
220
+ if result[:success]
221
+ puts "✅ Label '#{label}' removed from email"
222
+ else
223
+ puts "❌ Failed to remove label from email"
224
+ end
225
+ rescue RuntimeError => e
226
+ warn "❌ Failed to remove label from email: #{e.message}"
227
+ exit 1
228
+ end
229
+
230
+ desc "archive EMAIL_ID", "Archive an email"
231
+ def archive(email_id)
232
+ result = tool.archive_email(email_id)
233
+
234
+ if result[:success]
235
+ puts "✅ Email archived"
236
+ else
237
+ puts "❌ Failed to archive email"
238
+ end
239
+ rescue RuntimeError => e
240
+ warn "❌ Failed to archive email: #{e.message}"
241
+ exit 1
242
+ end
243
+
244
+ desc "trash EMAIL_ID", "Move an email to trash"
245
+ def trash(email_id)
246
+ result = tool.trash_email(email_id)
247
+
248
+ if result[:success]
249
+ puts "✅ Email moved to trash"
250
+ else
251
+ puts "❌ Failed to move email to trash"
252
+ end
253
+ rescue RuntimeError => e
254
+ warn "❌ Failed to move email to trash: #{e.message}"
255
+ exit 1
256
+ end
257
+
258
+ private
259
+
260
+ def tool
261
+ @tool ||= Service.new
262
+ end
263
+ end
264
+ end