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,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "thor"
5
+ require_relative "service"
6
+
7
+ module Notion
8
+ class CLI < Thor
9
+ desc "test", "Test the Notion API connection"
10
+ def test
11
+ response = tool.test_connection
12
+
13
+ if response[:ok]
14
+ puts "✅ Successfully connected to Notion"
15
+ puts " User: #{response[:user]}"
16
+ puts " Type: #{response[:type]}"
17
+ else
18
+ warn "❌ Authentication failed: #{response[:error]}"
19
+ end
20
+ rescue RuntimeError => e
21
+ puts "❌ Failed to connect to Notion: #{e.message}"
22
+ exit 1
23
+ end
24
+
25
+ desc "search_pages QUERY", "Search for pages in Notion"
26
+ method_option :limit, type: :numeric, default: 10, aliases: "-l", desc: "Maximum number of results"
27
+ def search_pages(query = "")
28
+ pages = tool.search_pages(query: query, page_size: options[:limit])
29
+
30
+ if pages && !pages.empty?
31
+ puts "📄 Found #{pages.count} pages:"
32
+ pages.each do |page|
33
+ puts " #{page[:title]}"
34
+ puts " ID: #{page[:id]}"
35
+ puts " URL: #{page[:url]}"
36
+ puts " Last edited: #{page[:last_edited_time]}"
37
+ puts
38
+ end
39
+ else
40
+ puts "📄 No pages found for query: '#{query}'"
41
+ end
42
+ rescue RuntimeError => e
43
+ warn "❌ Failed to search pages: #{e.message}"
44
+ exit 1
45
+ end
46
+
47
+ desc "search_databases QUERY", "Search for databases in Notion"
48
+ method_option :limit, type: :numeric, default: 10, aliases: "-l", desc: "Maximum number of results"
49
+ def search_databases(query = "")
50
+ databases = tool.search_databases(query: query, page_size: options[:limit])
51
+
52
+ if databases && !databases.empty?
53
+ puts "🗃️ Found #{databases.count} databases:"
54
+ databases.each do |database|
55
+ puts " #{database[:title]}"
56
+ puts " ID: #{database[:id]}"
57
+ puts " URL: #{database[:url]}"
58
+ puts " Last edited: #{database[:last_edited_time]}"
59
+ puts
60
+ end
61
+ else
62
+ puts "🗃️ No databases found for query: '#{query}'"
63
+ end
64
+ rescue RuntimeError => e
65
+ warn "❌ Failed to search databases: #{e.message}"
66
+ exit 1
67
+ end
68
+
69
+ desc "get_page PAGE_ID", "Get details of a specific page"
70
+ def get_page(page_id)
71
+ page = tool.get_page(page_id)
72
+
73
+ puts "📄 Page Details:"
74
+ puts " Title: #{page[:title]}"
75
+ puts " ID: #{page[:id]}"
76
+ puts " URL: #{page[:url]}"
77
+ puts " Created: #{page[:created_time]}"
78
+ puts " Last edited: #{page[:last_edited_time]}"
79
+ puts
80
+ puts "🏷️ Properties:"
81
+ page[:properties].each do |name, prop|
82
+ puts " #{name}: #{format_property(prop)}"
83
+ end
84
+ rescue RuntimeError => e
85
+ warn "❌ Failed to get page: #{e.message}"
86
+ exit 1
87
+ end
88
+
89
+ desc "get_content PAGE_ID", "Get text content of a page"
90
+ def get_content(page_id)
91
+ content = tool.get_page_content(page_id)
92
+
93
+ if content && !content.empty?
94
+ puts "📝 Page Content:"
95
+ puts content
96
+ else
97
+ puts "📝 No content found for this page"
98
+ end
99
+ rescue RuntimeError => e
100
+ warn "❌ Failed to get page content: #{e.message}"
101
+ exit 1
102
+ end
103
+
104
+ desc "query_database DATABASE_ID", "Query entries in a database"
105
+ method_option :limit, type: :numeric, default: 100, aliases: "-l", desc: "Maximum number of results"
106
+ method_option :cursor, type: :string, aliases: "-c", desc: "Pagination cursor from previous request"
107
+ method_option :page, type: :numeric, default: 1, aliases: "-p", desc: "Page number (for calculating item numbers)"
108
+ def query_database(database_id)
109
+ page_size = options[:limit]
110
+ start_cursor = options[:cursor]
111
+ page_num = options[:page]
112
+
113
+ result = tool.query_database(database_id, page_size: page_size, start_cursor: start_cursor)
114
+ entries = result[:entries]
115
+
116
+ if entries && !entries.empty?
117
+ # Calculate starting index based on page number
118
+ start_index = (page_num - 1) * page_size
119
+
120
+ puts "🗃️ Found #{entries.count} entries (Page #{page_num}):"
121
+ entries.each_with_index do |entry, i|
122
+ puts " #{start_index + i + 1}. #{entry[:title]}"
123
+ puts " ID: #{entry[:id]}"
124
+ puts " URL: #{entry[:url]}"
125
+ puts " Last edited: #{entry[:last_edited_time]}"
126
+ puts
127
+ end
128
+
129
+ if result[:has_more]
130
+ puts "📄 More entries available. To see next page, use:"
131
+ puts " mcpz notion query_database #{database_id} --cursor '#{result[:next_cursor]}' --page #{page_num + 1}"
132
+ else
133
+ puts "📄 End of database entries"
134
+ end
135
+ else
136
+ puts "🗃️ No entries found in database"
137
+ end
138
+ rescue RuntimeError => e
139
+ warn "❌ Failed to query database: #{e.message}"
140
+ exit 1
141
+ end
142
+
143
+ desc "list_users", "List all users in the workspace"
144
+ method_option :limit, type: :numeric, default: 100, aliases: "-l", desc: "Maximum number of results"
145
+ method_option :cursor, type: :string, aliases: "-c", desc: "Pagination cursor from previous request"
146
+ method_option :page, type: :numeric, default: 1, aliases: "-p", desc: "Page number (for calculating item numbers)"
147
+ def list_users
148
+ page_size = options[:limit]
149
+ start_cursor = options[:cursor]
150
+ page_num = options[:page]
151
+
152
+ result = tool.list_users(page_size: page_size, start_cursor: start_cursor)
153
+ users = result[:users]
154
+
155
+ if users && !users.empty?
156
+ # Calculate starting index based on page number
157
+ start_index = (page_num - 1) * page_size
158
+
159
+ puts "👥 Found #{users.count} users (Page #{page_num}):"
160
+ users.each_with_index do |user, i|
161
+ puts " #{start_index + i + 1}. #{user[:name] || "Unnamed"} (#{user[:type]})"
162
+ puts " ID: #{user[:id]}"
163
+ puts " Email: #{user[:email]}" if user[:email]
164
+ puts " Avatar: #{user[:avatar_url]}" if user[:avatar_url]
165
+ puts
166
+ end
167
+
168
+ if result[:has_more]
169
+ puts "📄 More users available. To see next page, use:"
170
+ puts " mcpz notion list_users --cursor '#{result[:next_cursor]}' --page #{page_num + 1}"
171
+ else
172
+ puts "📄 End of user list"
173
+ end
174
+ else
175
+ puts "👥 No users found"
176
+ end
177
+ rescue RuntimeError => e
178
+ warn "❌ Failed to list users: #{e.message}"
179
+ exit 1
180
+ end
181
+
182
+ desc "get_user USER_ID", "Get details of a specific user"
183
+ def get_user(user_id)
184
+ user = tool.get_user(user_id)
185
+
186
+ puts "👤 User Details:"
187
+ puts " Name: #{user[:name] || "Unnamed"}"
188
+ puts " Type: #{user[:type]}"
189
+ puts " ID: #{user[:id]}"
190
+ puts " Email: #{user[:email]}" if user[:email]
191
+ puts " Avatar: #{user[:avatar_url]}" if user[:avatar_url]
192
+ rescue RuntimeError => e
193
+ warn "❌ Failed to get user: #{e.message}"
194
+ exit 1
195
+ end
196
+
197
+ desc "bot_info", "Get information about the integration bot user"
198
+ def bot_info
199
+ bot = tool.get_bot_user
200
+
201
+ puts "🤖 Bot User Details:"
202
+ puts " Name: #{bot[:name] || "Unnamed"}"
203
+ puts " Type: #{bot[:type]}"
204
+ puts " ID: #{bot[:id]}"
205
+ puts " Workspace: #{bot[:bot][:workspace_name]}" if bot[:bot][:workspace_name]
206
+ puts " Owner: #{bot[:bot][:owner]}" if bot[:bot][:owner]
207
+ rescue RuntimeError => e
208
+ warn "❌ Failed to get bot info: #{e.message}"
209
+ exit 1
210
+ end
211
+
212
+ private
213
+
214
+ def tool
215
+ @tool ||= Service.new
216
+ end
217
+
218
+ def format_property(prop)
219
+ case prop["type"]
220
+ when "title"
221
+ prop["title"]&.map { |t| t["plain_text"] }&.join || ""
222
+ when "rich_text"
223
+ prop["rich_text"]&.map { |t| t["plain_text"] }&.join || ""
224
+ when "number"
225
+ prop["number"]&.to_s || ""
226
+ when "select"
227
+ prop["select"]&.dig("name") || ""
228
+ when "multi_select"
229
+ prop["multi_select"]&.map { |s| s["name"] }&.join(", ") || ""
230
+ when "date"
231
+ prop["date"]&.dig("start") || ""
232
+ when "checkbox"
233
+ prop["checkbox"] ? "☑" : "☐"
234
+ when "url"
235
+ prop["url"] || ""
236
+ when "email"
237
+ prop["email"] || ""
238
+ when "phone_number"
239
+ prop["phone_number"] || ""
240
+ else
241
+ "[#{prop["type"]}]"
242
+ end
243
+ end
244
+ end
245
+ end