universal-mcp-applications 0.1.25__py3-none-any.whl → 0.1.26__py3-none-any.whl
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.
Potentially problematic release.
This version of universal-mcp-applications might be problematic. Click here for more details.
- universal_mcp/applications/outlook/app.py +253 -209
- universal_mcp/applications/reddit/app.py +30 -47
- {universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.26.dist-info}/METADATA +1 -1
- {universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.26.dist-info}/RECORD +6 -6
- {universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.26.dist-info}/WHEEL +0 -0
- {universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.26.dist-info}/licenses/LICENSE +0 -0
|
@@ -10,143 +10,176 @@ class OutlookApp(APIApplication):
|
|
|
10
10
|
super().__init__(name="outlook", integration=integration, **kwargs)
|
|
11
11
|
self.base_url = "https://graph.microsoft.com/v1.0"
|
|
12
12
|
|
|
13
|
-
def
|
|
13
|
+
def reply_to_email(
|
|
14
14
|
self,
|
|
15
15
|
message_id: str,
|
|
16
|
+
comment: str,
|
|
16
17
|
user_id: str | None = None,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
) -> Any:
|
|
18
|
+
attachments: list[dict[str, Any]] | None = None,
|
|
19
|
+
) -> dict[str, Any]:
|
|
20
20
|
"""
|
|
21
|
-
Replies to
|
|
21
|
+
Replies to a specific email message.
|
|
22
22
|
|
|
23
23
|
Args:
|
|
24
|
-
message_id (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
message_id (str): The ID of the email message to reply to.
|
|
25
|
+
comment (str): The body of the reply.
|
|
26
|
+
user_id (str, optional): The ID of the user to send the reply from. Defaults to the authenticated user.
|
|
27
|
+
attachments (list[dict[str, Any]], optional): A list of attachment objects to include in the reply.
|
|
28
|
+
Each attachment dictionary should conform to the Microsoft Graph API specification.
|
|
29
|
+
Example:
|
|
30
|
+
[
|
|
31
|
+
{
|
|
32
|
+
"@odata.type": "#microsoft.graph.fileAttachment",
|
|
33
|
+
"name": "attachment.txt",
|
|
34
|
+
"contentType": "text/plain",
|
|
35
|
+
"contentBytes": "SGVsbG8gV29ybGQh"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
28
38
|
|
|
29
39
|
Returns:
|
|
30
|
-
Any:
|
|
40
|
+
dict[str, Any]: A dictionary confirming the reply action.
|
|
31
41
|
|
|
32
42
|
Raises:
|
|
33
|
-
HTTPStatusError:
|
|
43
|
+
HTTPStatusError: If the API request fails.
|
|
44
|
+
ValueError: If the user_id cannot be retrieved or message_id is missing.
|
|
34
45
|
|
|
35
46
|
Tags:
|
|
36
|
-
|
|
47
|
+
important
|
|
37
48
|
"""
|
|
38
|
-
# If user_id is not provided, get it automatically
|
|
39
49
|
if user_id is None:
|
|
40
|
-
user_info = self.
|
|
50
|
+
user_info = self.get_my_profile()
|
|
41
51
|
user_id = user_info.get("userPrincipalName")
|
|
42
52
|
if not user_id:
|
|
43
|
-
raise ValueError("Could not retrieve user ID from
|
|
44
|
-
if message_id
|
|
45
|
-
raise ValueError("Missing required parameter '
|
|
46
|
-
|
|
47
|
-
request_body_data = {
|
|
48
|
-
|
|
49
|
-
"message":
|
|
50
|
-
|
|
51
|
-
request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
|
|
53
|
+
raise ValueError("Could not retrieve user ID from get_my_profile response.")
|
|
54
|
+
if not message_id:
|
|
55
|
+
raise ValueError("Missing required parameter 'message_id'.")
|
|
56
|
+
|
|
57
|
+
request_body_data = {"comment": comment}
|
|
58
|
+
if attachments:
|
|
59
|
+
request_body_data["message"] = {"attachments": attachments}
|
|
60
|
+
|
|
52
61
|
url = f"{self.base_url}/users/{user_id}/messages/{message_id}/reply"
|
|
53
|
-
|
|
62
|
+
|
|
54
63
|
response = self._post(
|
|
55
64
|
url,
|
|
56
65
|
data=request_body_data,
|
|
57
|
-
params=
|
|
66
|
+
params={},
|
|
58
67
|
content_type="application/json",
|
|
59
68
|
)
|
|
60
69
|
return self._handle_response(response)
|
|
61
70
|
|
|
62
|
-
def
|
|
71
|
+
def send_email(
|
|
63
72
|
self,
|
|
64
|
-
|
|
73
|
+
subject: str,
|
|
74
|
+
body: str,
|
|
75
|
+
to_recipients: list[str],
|
|
65
76
|
user_id: str | None = None,
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
cc_recipients: list[str] | None = None,
|
|
78
|
+
bcc_recipients: list[str] | None = None,
|
|
79
|
+
attachments: list[dict[str, Any]] | None = None,
|
|
80
|
+
body_content_type: str = "Text",
|
|
81
|
+
save_to_sent_items: bool = True,
|
|
82
|
+
) -> dict[str, Any]:
|
|
68
83
|
"""
|
|
69
|
-
Sends a new email
|
|
84
|
+
Sends a new email.
|
|
70
85
|
|
|
71
86
|
Args:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
87
|
+
subject (str): The subject of the email.
|
|
88
|
+
body (str): The body of the email.
|
|
89
|
+
to_recipients (list[str]): A list of email addresses for the 'To' recipients.
|
|
90
|
+
user_id (str, optional): The ID of the user to send the email from. Defaults to the authenticated user.
|
|
91
|
+
cc_recipients (list[str], optional): A list of email addresses for the 'Cc' recipients.
|
|
92
|
+
bcc_recipients (list[str], optional): A list of email addresses for the 'Bcc' recipients.
|
|
93
|
+
attachments (list[dict[str, Any]], optional): A list of attachment objects. See `reply_to_email` for an example.
|
|
94
|
+
body_content_type (str, optional): The content type of the email body, e.g., "Text" or "HTML". Defaults to "Text".
|
|
95
|
+
save_to_sent_items (bool, optional): Whether to save the email to the 'Sent Items' folder. Defaults to True.
|
|
75
96
|
|
|
76
97
|
Returns:
|
|
77
|
-
Any:
|
|
98
|
+
dict[str, Any]: A dictionary confirming the send action.
|
|
78
99
|
|
|
79
100
|
Raises:
|
|
80
|
-
HTTPStatusError:
|
|
101
|
+
HTTPStatusError: If the API request fails.
|
|
102
|
+
ValueError: If the user_id cannot be retrieved.
|
|
81
103
|
|
|
82
104
|
Tags:
|
|
83
|
-
|
|
105
|
+
important
|
|
84
106
|
"""
|
|
85
|
-
# If user_id is not provided, get it automatically
|
|
86
107
|
if user_id is None:
|
|
87
|
-
user_info = self.
|
|
108
|
+
user_info = self.get_my_profile()
|
|
88
109
|
user_id = user_info.get("userPrincipalName")
|
|
89
110
|
if not user_id:
|
|
90
|
-
raise ValueError("Could not retrieve user ID from
|
|
91
|
-
|
|
111
|
+
raise ValueError("Could not retrieve user ID from get_my_profile response.")
|
|
112
|
+
|
|
113
|
+
message = {
|
|
114
|
+
"subject": subject,
|
|
115
|
+
"body": {"contentType": body_content_type, "content": body},
|
|
116
|
+
"toRecipients": [{"emailAddress": {"address": email}} for email in to_recipients],
|
|
117
|
+
}
|
|
118
|
+
if cc_recipients:
|
|
119
|
+
message["ccRecipients"] = [{"emailAddress": {"address": email}} for email in cc_recipients]
|
|
120
|
+
if bcc_recipients:
|
|
121
|
+
message["bccRecipients"] = [{"emailAddress": {"address": email}} for email in bcc_recipients]
|
|
122
|
+
if attachments:
|
|
123
|
+
message["attachments"] = attachments
|
|
124
|
+
|
|
92
125
|
request_body_data = {
|
|
93
126
|
"message": message,
|
|
94
|
-
"saveToSentItems":
|
|
127
|
+
"saveToSentItems": save_to_sent_items,
|
|
95
128
|
}
|
|
96
|
-
|
|
129
|
+
|
|
97
130
|
url = f"{self.base_url}/users/{user_id}/sendMail"
|
|
98
|
-
|
|
131
|
+
|
|
99
132
|
response = self._post(
|
|
100
133
|
url,
|
|
101
134
|
data=request_body_data,
|
|
102
|
-
params=
|
|
135
|
+
params={},
|
|
103
136
|
content_type="application/json",
|
|
104
137
|
)
|
|
105
138
|
return self._handle_response(response)
|
|
106
139
|
|
|
107
|
-
def
|
|
140
|
+
def get_email_folder(
|
|
108
141
|
self,
|
|
109
|
-
|
|
142
|
+
folder_id: str,
|
|
110
143
|
user_id: str | None = None,
|
|
111
|
-
|
|
144
|
+
include_hidden: bool | None = None,
|
|
112
145
|
select: list[str] | None = None,
|
|
113
146
|
expand: list[str] | None = None,
|
|
114
|
-
) -> Any:
|
|
147
|
+
) -> dict[str, Any]:
|
|
115
148
|
"""
|
|
116
|
-
Retrieves a specific
|
|
149
|
+
Retrieves a specific email folder's metadata by its ID.
|
|
117
150
|
|
|
118
151
|
Args:
|
|
119
|
-
|
|
120
|
-
user_id (
|
|
121
|
-
|
|
122
|
-
select (
|
|
123
|
-
expand (
|
|
152
|
+
folder_id (str): The unique identifier for the mail folder.
|
|
153
|
+
user_id (str, optional): The ID of the user who owns the folder. Defaults to the authenticated user.
|
|
154
|
+
include_hidden (bool, optional): If true, includes hidden folders in the results.
|
|
155
|
+
select (list[str], optional): A list of properties to return.
|
|
156
|
+
expand (list[str], optional): A list of related entities to expand.
|
|
124
157
|
|
|
125
158
|
Returns:
|
|
126
|
-
Any:
|
|
159
|
+
dict[str, Any]: A dictionary containing the mail folder's metadata.
|
|
127
160
|
|
|
128
161
|
Raises:
|
|
129
|
-
HTTPStatusError:
|
|
130
|
-
|
|
162
|
+
HTTPStatusError: If the API request fails.
|
|
163
|
+
ValueError: If user_id cannot be retrieved or folder_id is missing.
|
|
131
164
|
Tags:
|
|
132
|
-
|
|
165
|
+
important
|
|
133
166
|
"""
|
|
134
|
-
# If user_id is not provided, get it automatically
|
|
135
167
|
if user_id is None:
|
|
136
|
-
user_info = self.
|
|
168
|
+
user_info = self.get_my_profile()
|
|
137
169
|
user_id = user_info.get("userPrincipalName")
|
|
138
170
|
if not user_id:
|
|
139
|
-
raise ValueError("Could not retrieve user ID from
|
|
140
|
-
if
|
|
141
|
-
raise ValueError("Missing required parameter '
|
|
142
|
-
|
|
171
|
+
raise ValueError("Could not retrieve user ID from get_my_profile response.")
|
|
172
|
+
if not folder_id:
|
|
173
|
+
raise ValueError("Missing required parameter 'folder_id'.")
|
|
174
|
+
|
|
175
|
+
url = f"{self.base_url}/users/{user_id}/mailFolders/{folder_id}"
|
|
143
176
|
select_str = ",".join(select) if select else None
|
|
144
177
|
expand_str = ",".join(expand) if expand else None
|
|
145
178
|
|
|
146
179
|
query_params = {
|
|
147
180
|
k: v
|
|
148
181
|
for k, v in [
|
|
149
|
-
("includeHiddenFolders",
|
|
182
|
+
("includeHiddenFolders", include_hidden),
|
|
150
183
|
("$select", select_str),
|
|
151
184
|
("$expand", expand_str),
|
|
152
185
|
]
|
|
@@ -155,11 +188,11 @@ class OutlookApp(APIApplication):
|
|
|
155
188
|
response = self._get(url, params=query_params)
|
|
156
189
|
return self._handle_response(response)
|
|
157
190
|
|
|
158
|
-
def
|
|
191
|
+
def list_emails(
|
|
159
192
|
self,
|
|
160
193
|
user_id: str | None = None,
|
|
161
194
|
select: list[str] = ["bodyPreview"],
|
|
162
|
-
|
|
195
|
+
include_hidden: bool | None = None,
|
|
163
196
|
top: int | None = None,
|
|
164
197
|
skip: int | None = None,
|
|
165
198
|
search: str | None = None,
|
|
@@ -169,70 +202,44 @@ class OutlookApp(APIApplication):
|
|
|
169
202
|
expand: list[str] | None = None,
|
|
170
203
|
) -> dict[str, Any]:
|
|
171
204
|
"""
|
|
172
|
-
Retrieves a list of
|
|
173
|
-
|
|
174
|
-
IMPORTANT LIMITATIONS (Microsoft Graph API restrictions):
|
|
175
|
-
- `search` cannot be used with `filter`
|
|
176
|
-
- `search` cannot be used with `orderby`
|
|
177
|
-
- `search` cannot be used with `skip` (use pagination via @odata.nextLink and get_next_page instead)
|
|
178
|
-
- When using `search`, pagination uses $skiptoken instead of $skip
|
|
205
|
+
Retrieves a list of emails from a user's mailbox.
|
|
179
206
|
|
|
180
207
|
Args:
|
|
181
|
-
user_id (
|
|
182
|
-
select (list):
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
top (integer): Specify the number of items to be included in the result Example: '50'.
|
|
192
|
-
skip (integer): Specify the number of items to skip in the result. Cannot be used with 'search'. Example: '10'.
|
|
193
|
-
search (string): Search items by search phrases. Cannot be used with 'filter', 'orderby', or 'skip'.
|
|
194
|
-
filter (string): Filter items by property values. Cannot be used with 'search'.
|
|
195
|
-
count (boolean): Include count of items
|
|
196
|
-
orderby (array): Order items by property values. Cannot be used with 'search'.
|
|
197
|
-
expand (array): Expand related entities
|
|
208
|
+
user_id (str, optional): The ID of the user. Defaults to the authenticated user.
|
|
209
|
+
select (list[str], optional): A list of properties to return for each email. Defaults to ['bodyPreview'].
|
|
210
|
+
include_hidden (bool, optional): If true, includes hidden messages.
|
|
211
|
+
top (int, optional): The maximum number of emails to return.
|
|
212
|
+
skip (int, optional): The number of emails to skip. Cannot be used with 'search'.
|
|
213
|
+
search (str, optional): A search query. Cannot be used with 'filter', 'orderby', or 'skip'.
|
|
214
|
+
filter (str, optional): A filter query. Cannot be used with 'search'.
|
|
215
|
+
count (bool, optional): If true, includes the total count of emails in the response.
|
|
216
|
+
orderby (list[str], optional): A list of properties to sort the results by. Cannot be used with 'search'.
|
|
217
|
+
expand (list[str], optional): A list of related entities to expand.
|
|
198
218
|
|
|
199
219
|
Returns:
|
|
200
|
-
dict[str, Any]:
|
|
220
|
+
dict[str, Any]: A dictionary containing a list of emails and pagination information.
|
|
201
221
|
|
|
202
222
|
Raises:
|
|
203
|
-
ValueError: If incompatible parameters are used together (search with filter
|
|
204
|
-
HTTPStatusError:
|
|
205
|
-
|
|
223
|
+
ValueError: If incompatible parameters are used together (e.g., 'search' with 'filter').
|
|
224
|
+
HTTPStatusError: If the API request fails.
|
|
206
225
|
Tags:
|
|
207
|
-
|
|
226
|
+
important
|
|
208
227
|
"""
|
|
209
228
|
if search:
|
|
210
229
|
if filter:
|
|
211
|
-
raise ValueError(
|
|
212
|
-
"The 'search' parameter cannot be used together with 'filter'. "
|
|
213
|
-
"This is a Microsoft Graph API restriction. Please use either search or filter, not both."
|
|
214
|
-
)
|
|
230
|
+
raise ValueError("The 'search' parameter cannot be used with 'filter'.")
|
|
215
231
|
if orderby:
|
|
216
|
-
raise ValueError(
|
|
217
|
-
"The 'search' parameter cannot be used together with 'orderby'. "
|
|
218
|
-
"This is a Microsoft Graph API restriction. When using search, results are sorted by relevance."
|
|
219
|
-
)
|
|
232
|
+
raise ValueError("The 'search' parameter cannot be used with 'orderby'.")
|
|
220
233
|
if skip:
|
|
221
|
-
raise ValueError(
|
|
222
|
-
"The 'search' parameter cannot be used together with 'skip'. "
|
|
223
|
-
"When using search, use pagination via @odata.nextLink and the get_next_page function instead."
|
|
224
|
-
)
|
|
234
|
+
raise ValueError("The 'search' parameter cannot be used with 'skip'. Use pagination via @odata.nextLink instead.")
|
|
225
235
|
|
|
226
|
-
# If user_id is not provided, get it automatically
|
|
227
236
|
if user_id is None:
|
|
228
|
-
user_info = self.
|
|
237
|
+
user_info = self.get_my_profile()
|
|
229
238
|
user_id = user_info.get("userPrincipalName")
|
|
230
239
|
if not user_id:
|
|
231
|
-
raise ValueError("Could not retrieve user ID from
|
|
240
|
+
raise ValueError("Could not retrieve user ID from get_my_profile response.")
|
|
232
241
|
|
|
233
242
|
url = f"{self.base_url}/users/{user_id}/messages"
|
|
234
|
-
|
|
235
|
-
# Handle list parameters by joining with commas
|
|
236
243
|
select_str = ",".join(select) if select else None
|
|
237
244
|
orderby_str = ",".join(orderby) if orderby else None
|
|
238
245
|
expand_str = ",".join(expand) if expand else None
|
|
@@ -240,7 +247,7 @@ class OutlookApp(APIApplication):
|
|
|
240
247
|
query_params = {
|
|
241
248
|
k: v
|
|
242
249
|
for k, v in [
|
|
243
|
-
("includeHiddenMessages",
|
|
250
|
+
("includeHiddenMessages", include_hidden),
|
|
244
251
|
("$top", top),
|
|
245
252
|
("$skip", skip),
|
|
246
253
|
("$search", search),
|
|
@@ -256,41 +263,41 @@ class OutlookApp(APIApplication):
|
|
|
256
263
|
response = self._get(url, params=query_params)
|
|
257
264
|
return self._handle_response(response)
|
|
258
265
|
|
|
259
|
-
def
|
|
266
|
+
def get_email(
|
|
260
267
|
self,
|
|
261
268
|
message_id: str,
|
|
262
269
|
user_id: str | None = None,
|
|
263
|
-
|
|
270
|
+
include_hidden: bool | None = None,
|
|
264
271
|
select: list[str] | None = None,
|
|
265
272
|
expand: list[str] | None = None,
|
|
266
|
-
) -> Any:
|
|
273
|
+
) -> dict[str, Any]:
|
|
267
274
|
"""
|
|
268
|
-
Retrieves a specific email
|
|
275
|
+
Retrieves a specific email by its ID.
|
|
269
276
|
|
|
270
277
|
Args:
|
|
271
|
-
message_id (
|
|
272
|
-
user_id (
|
|
273
|
-
|
|
274
|
-
select (
|
|
275
|
-
expand (
|
|
278
|
+
message_id (str): The unique identifier for the email.
|
|
279
|
+
user_id (str, optional): The ID of the user who owns the email. Defaults to the authenticated user.
|
|
280
|
+
include_hidden (bool, optional): If true, includes hidden messages.
|
|
281
|
+
select (list[str], optional): A list of properties to return.
|
|
282
|
+
expand (list[str], optional): A list of related entities to expand.
|
|
276
283
|
|
|
277
284
|
Returns:
|
|
278
|
-
Any:
|
|
285
|
+
dict[str, Any]: A dictionary containing the email's details.
|
|
279
286
|
|
|
280
287
|
Raises:
|
|
281
|
-
HTTPStatusError:
|
|
282
|
-
|
|
288
|
+
HTTPStatusError: If the API request fails.
|
|
289
|
+
ValueError: If user_id cannot be retrieved or message_id is missing.
|
|
283
290
|
Tags:
|
|
284
|
-
|
|
291
|
+
important
|
|
285
292
|
"""
|
|
286
|
-
# If user_id is not provided, get it automatically
|
|
287
293
|
if user_id is None:
|
|
288
|
-
user_info = self.
|
|
294
|
+
user_info = self.get_my_profile()
|
|
289
295
|
user_id = user_info.get("userPrincipalName")
|
|
290
296
|
if not user_id:
|
|
291
|
-
raise ValueError("Could not retrieve user ID from
|
|
292
|
-
if message_id
|
|
293
|
-
raise ValueError("Missing required parameter '
|
|
297
|
+
raise ValueError("Could not retrieve user ID from get_my_profile response.")
|
|
298
|
+
if not message_id:
|
|
299
|
+
raise ValueError("Missing required parameter 'message_id'.")
|
|
300
|
+
|
|
294
301
|
url = f"{self.base_url}/users/{user_id}/messages/{message_id}"
|
|
295
302
|
select_str = ",".join(select) if select else None
|
|
296
303
|
expand_str = ",".join(expand) if expand else None
|
|
@@ -298,7 +305,7 @@ class OutlookApp(APIApplication):
|
|
|
298
305
|
query_params = {
|
|
299
306
|
k: v
|
|
300
307
|
for k, v in [
|
|
301
|
-
("includeHiddenMessages",
|
|
308
|
+
("includeHiddenMessages", include_hidden),
|
|
302
309
|
("$select", select_str),
|
|
303
310
|
("$expand", expand_str),
|
|
304
311
|
]
|
|
@@ -307,37 +314,36 @@ class OutlookApp(APIApplication):
|
|
|
307
314
|
response = self._get(url, params=query_params)
|
|
308
315
|
return self._handle_response(response)
|
|
309
316
|
|
|
310
|
-
def
|
|
317
|
+
def delete_email(self, message_id: str, user_id: str | None = None) -> dict[str, Any]:
|
|
311
318
|
"""
|
|
312
|
-
Permanently deletes a specific email
|
|
319
|
+
Permanently deletes a specific email by its ID.
|
|
313
320
|
|
|
314
321
|
Args:
|
|
315
|
-
message_id (
|
|
316
|
-
user_id (
|
|
322
|
+
message_id (str): The unique identifier for the email to be deleted.
|
|
323
|
+
user_id (str, optional): The ID of the user who owns the email. Defaults to the authenticated user.
|
|
317
324
|
|
|
318
325
|
Returns:
|
|
319
|
-
Any:
|
|
326
|
+
dict[str, Any]: A dictionary confirming the deletion.
|
|
320
327
|
|
|
321
328
|
Raises:
|
|
322
|
-
HTTPStatusError:
|
|
323
|
-
|
|
329
|
+
HTTPStatusError: If the API request fails.
|
|
330
|
+
ValueError: If user_id cannot be retrieved or message_id is missing.
|
|
324
331
|
Tags:
|
|
325
|
-
|
|
332
|
+
important
|
|
326
333
|
"""
|
|
327
|
-
# If user_id is not provided, get it automatically
|
|
328
334
|
if user_id is None:
|
|
329
|
-
user_info = self.
|
|
335
|
+
user_info = self.get_my_profile()
|
|
330
336
|
user_id = user_info.get("userPrincipalName")
|
|
331
337
|
if not user_id:
|
|
332
|
-
raise ValueError("Could not retrieve user ID from
|
|
333
|
-
if message_id
|
|
334
|
-
raise ValueError("Missing required parameter '
|
|
338
|
+
raise ValueError("Could not retrieve user ID from get_my_profile response.")
|
|
339
|
+
if not message_id:
|
|
340
|
+
raise ValueError("Missing required parameter 'message_id'.")
|
|
341
|
+
|
|
335
342
|
url = f"{self.base_url}/users/{user_id}/messages/{message_id}"
|
|
336
|
-
|
|
337
|
-
response = self._delete(url, params=query_params)
|
|
343
|
+
response = self._delete(url, params={})
|
|
338
344
|
return self._handle_response(response)
|
|
339
345
|
|
|
340
|
-
def
|
|
346
|
+
def list_email_attachments(
|
|
341
347
|
self,
|
|
342
348
|
message_id: str,
|
|
343
349
|
user_id: str | None = None,
|
|
@@ -351,60 +357,44 @@ class OutlookApp(APIApplication):
|
|
|
351
357
|
expand: list[str] | None = None,
|
|
352
358
|
) -> dict[str, Any]:
|
|
353
359
|
"""
|
|
354
|
-
Retrieves attachments for a specific email
|
|
355
|
-
|
|
356
|
-
IMPORTANT LIMITATIONS (Microsoft Graph API restrictions):
|
|
357
|
-
- `search` cannot be used with `filter`
|
|
358
|
-
- `search` cannot be used with `orderby`
|
|
359
|
-
- `search` cannot be used with `skip` (use pagination via @odata.nextLink and get_next_page instead)
|
|
360
|
+
Retrieves attachments for a specific email.
|
|
360
361
|
|
|
361
362
|
Args:
|
|
362
|
-
message_id (
|
|
363
|
-
user_id (
|
|
364
|
-
top (
|
|
365
|
-
skip (
|
|
366
|
-
search (
|
|
367
|
-
filter (
|
|
368
|
-
count (
|
|
369
|
-
orderby (
|
|
370
|
-
select (
|
|
371
|
-
expand (
|
|
363
|
+
message_id (str): The unique identifier for the email.
|
|
364
|
+
user_id (str, optional): The ID of the user who owns the email. Defaults to the authenticated user.
|
|
365
|
+
top (int, optional): The maximum number of attachments to return.
|
|
366
|
+
skip (int, optional): The number of attachments to skip. Cannot be used with 'search'.
|
|
367
|
+
search (str, optional): A search query. Cannot be used with 'filter', 'orderby', or 'skip'.
|
|
368
|
+
filter (str, optional): A filter query. Cannot be used with 'search'.
|
|
369
|
+
count (bool, optional): If true, includes the total count of attachments.
|
|
370
|
+
orderby (list[str], optional): A list of properties to sort by. Cannot be used with 'search'.
|
|
371
|
+
select (list[str], optional): A list of properties to return.
|
|
372
|
+
expand (list[str], optional): A list of related entities to expand.
|
|
372
373
|
|
|
373
374
|
Returns:
|
|
374
|
-
dict[str, Any]:
|
|
375
|
+
dict[str, Any]: A dictionary containing a list of attachments.
|
|
375
376
|
|
|
376
377
|
Raises:
|
|
377
|
-
ValueError: If incompatible parameters are used together
|
|
378
|
-
HTTPStatusError:
|
|
379
|
-
|
|
378
|
+
ValueError: If incompatible parameters are used together.
|
|
379
|
+
HTTPStatusError: If the API request fails.
|
|
380
380
|
Tags:
|
|
381
|
-
|
|
381
|
+
important
|
|
382
382
|
"""
|
|
383
383
|
if search:
|
|
384
384
|
if filter:
|
|
385
|
-
raise ValueError(
|
|
386
|
-
"The 'search' parameter cannot be used together with 'filter'. "
|
|
387
|
-
"This is a Microsoft Graph API restriction. Please use either search or filter, not both."
|
|
388
|
-
)
|
|
385
|
+
raise ValueError("The 'search' parameter cannot be used with 'filter'.")
|
|
389
386
|
if orderby:
|
|
390
|
-
raise ValueError(
|
|
391
|
-
"The 'search' parameter cannot be used together with 'orderby'. "
|
|
392
|
-
"This is a Microsoft Graph API restriction. When using search, results are sorted by relevance."
|
|
393
|
-
)
|
|
387
|
+
raise ValueError("The 'search' parameter cannot be used with 'orderby'.")
|
|
394
388
|
if skip:
|
|
395
|
-
raise ValueError(
|
|
396
|
-
"The 'search' parameter cannot be used together with 'skip'. "
|
|
397
|
-
"When using search, use pagination via @odata.nextLink and the get_next_page function instead."
|
|
398
|
-
)
|
|
389
|
+
raise ValueError("The 'search' parameter cannot be used with 'skip'. Use pagination via @odata.nextLink instead.")
|
|
399
390
|
|
|
400
|
-
# If user_id is not provided, get it automatically
|
|
401
391
|
if user_id is None:
|
|
402
|
-
user_info = self.
|
|
392
|
+
user_info = self.get_my_profile()
|
|
403
393
|
user_id = user_info.get("userPrincipalName")
|
|
404
394
|
if not user_id:
|
|
405
|
-
raise ValueError("Could not retrieve user ID from
|
|
406
|
-
if message_id
|
|
407
|
-
raise ValueError("Missing required parameter '
|
|
395
|
+
raise ValueError("Could not retrieve user ID from get_my_profile response.")
|
|
396
|
+
if not message_id:
|
|
397
|
+
raise ValueError("Missing required parameter 'message_id'.")
|
|
408
398
|
|
|
409
399
|
url = f"{self.base_url}/users/{user_id}/messages/{message_id}/attachments"
|
|
410
400
|
orderby_str = ",".join(orderby) if orderby else None
|
|
@@ -428,53 +418,107 @@ class OutlookApp(APIApplication):
|
|
|
428
418
|
response = self._get(url, params=query_params)
|
|
429
419
|
return self._handle_response(response)
|
|
430
420
|
|
|
431
|
-
def
|
|
421
|
+
def get_attachment(
|
|
432
422
|
self,
|
|
423
|
+
message_id: str,
|
|
424
|
+
attachment_id: str,
|
|
425
|
+
user_id: str | None = None,
|
|
433
426
|
) -> dict[str, Any]:
|
|
434
427
|
"""
|
|
435
|
-
|
|
428
|
+
Retrieves a specific attachment from an email message and formats it as a dictionary.
|
|
436
429
|
|
|
430
|
+
Args:
|
|
431
|
+
message_id (str): The ID of the email message.
|
|
432
|
+
attachment_id (str): The ID of the attachment.
|
|
433
|
+
user_id (str, optional): The ID of the user. Defaults to the authenticated user.
|
|
437
434
|
|
|
438
435
|
Returns:
|
|
439
|
-
dict[str, Any]:
|
|
436
|
+
dict[str, Any]: A dictionary containing the attachment details:
|
|
437
|
+
- 'type' (str): The general type of the attachment (e.g., "image", "audio", "video", "file").
|
|
438
|
+
- 'data' (str): The base64 encoded content of the attachment.
|
|
439
|
+
- 'mime_type' (str): The MIME type of the attachment.
|
|
440
|
+
- 'file_name' (str): The name of the attachment file.
|
|
441
|
+
Tags:
|
|
442
|
+
important
|
|
443
|
+
"""
|
|
444
|
+
if user_id is None:
|
|
445
|
+
user_info = self.get_my_profile()
|
|
446
|
+
user_id = user_info.get("userPrincipalName")
|
|
447
|
+
if not user_id:
|
|
448
|
+
raise ValueError("Could not retrieve user ID.")
|
|
449
|
+
if not message_id or not attachment_id:
|
|
450
|
+
raise ValueError("Missing required parameter 'message_id' or 'attachment_id'.")
|
|
440
451
|
|
|
441
|
-
|
|
442
|
-
HTTPStatusError: Raised when the API request fails with detailed error information including status code and response body.
|
|
452
|
+
url = f"{self.base_url}/users/{user_id}/messages/{message_id}/attachments/{attachment_id}"
|
|
443
453
|
|
|
444
|
-
|
|
445
|
-
|
|
454
|
+
response = self._get(url, params={})
|
|
455
|
+
attachment_data = self._handle_response(response)
|
|
456
|
+
|
|
457
|
+
content_type = attachment_data.get("contentType", "application/octet-stream")
|
|
458
|
+
attachment_type = content_type.split("/")[0] if "/" in content_type else "file"
|
|
459
|
+
if attachment_type not in ["image", "audio", "video", "text"]:
|
|
460
|
+
attachment_type = "file"
|
|
461
|
+
|
|
462
|
+
return {
|
|
463
|
+
"type": attachment_type,
|
|
464
|
+
"data": attachment_data.get("contentBytes"),
|
|
465
|
+
"mime_type": content_type,
|
|
466
|
+
"file_name": attachment_data.get("name"),
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
def get_my_profile(self) -> dict[str, Any]:
|
|
470
|
+
"""
|
|
471
|
+
Fetches the userPrincipalName for the currently authenticated user.
|
|
472
|
+
|
|
473
|
+
Returns:
|
|
474
|
+
dict[str, Any]: A dictionary containing the user's principal name.
|
|
475
|
+
|
|
476
|
+
Raises:
|
|
477
|
+
HTTPStatusError: If the API request fails.
|
|
446
478
|
"""
|
|
447
479
|
url = f"{self.base_url}/me"
|
|
448
|
-
query_params = {
|
|
449
|
-
"$select": "userPrincipalName",
|
|
450
|
-
}
|
|
480
|
+
query_params = {"$select": "userPrincipalName"}
|
|
451
481
|
response = self._get(url, params=query_params)
|
|
452
482
|
return self._handle_response(response)
|
|
453
483
|
|
|
454
|
-
def
|
|
484
|
+
def get_next_page_results(self, url: str) -> dict[str, Any]:
|
|
455
485
|
"""
|
|
456
|
-
|
|
486
|
+
Retrieves the next page of results from a paginated API response.
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
url (str): The full URL for the next page of results (@odata.nextLink).
|
|
490
|
+
|
|
491
|
+
Returns:
|
|
492
|
+
dict[str, Any]: A dictionary containing the next page of results.
|
|
493
|
+
|
|
494
|
+
Raises:
|
|
495
|
+
ValueError: If the URL is missing or invalid.
|
|
496
|
+
Tags:
|
|
497
|
+
important
|
|
457
498
|
"""
|
|
458
499
|
if not url:
|
|
459
500
|
raise ValueError("Missing required parameter 'url'.")
|
|
460
501
|
if not url.startswith(self.base_url):
|
|
461
|
-
raise ValueError(f"The provided URL
|
|
502
|
+
raise ValueError(f"The provided URL must start with '{self.base_url}'.")
|
|
503
|
+
|
|
462
504
|
relative_part = url[len(self.base_url) :]
|
|
463
505
|
parsed_relative = urlparse(relative_part)
|
|
464
506
|
path_only = parsed_relative.path
|
|
465
507
|
params = {k: v[0] for k, v in parse_qs(parsed_relative.query).items()}
|
|
508
|
+
|
|
466
509
|
response = self._get(path_only, params=params)
|
|
467
510
|
return self._handle_response(response)
|
|
468
511
|
|
|
469
512
|
def list_tools(self):
|
|
470
513
|
return [
|
|
471
|
-
self.
|
|
472
|
-
self.
|
|
473
|
-
self.
|
|
474
|
-
self.
|
|
475
|
-
self.
|
|
476
|
-
self.
|
|
477
|
-
self.
|
|
478
|
-
self.
|
|
479
|
-
self.
|
|
514
|
+
self.reply_to_email,
|
|
515
|
+
self.send_email,
|
|
516
|
+
self.get_email_folder,
|
|
517
|
+
self.list_emails,
|
|
518
|
+
self.get_email,
|
|
519
|
+
self.delete_email,
|
|
520
|
+
self.list_email_attachments,
|
|
521
|
+
self.get_attachment,
|
|
522
|
+
self.get_my_profile,
|
|
523
|
+
self.get_next_page_results,
|
|
480
524
|
]
|
|
@@ -44,9 +44,7 @@ class RedditApp(APIApplication):
|
|
|
44
44
|
"User-Agent": "agentr-reddit-app/0.1 by AgentR",
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
def get_subreddit_posts(
|
|
48
|
-
self, subreddit: str, limit: int = 5, timeframe: str = "day"
|
|
49
|
-
) -> dict[str, Any]:
|
|
47
|
+
def get_subreddit_posts(self, subreddit: str, limit: int = 5, timeframe: str = "day") -> dict[str, Any]:
|
|
50
48
|
"""
|
|
51
49
|
Fetches a specified number of top-rated posts from a particular subreddit, allowing results to be filtered by a specific timeframe (e.g., 'day', 'week'). This is a simplified version compared to `get_subreddit_top_posts`, which uses more complex pagination parameters instead of a direct time filter.
|
|
52
50
|
|
|
@@ -56,7 +54,7 @@ class RedditApp(APIApplication):
|
|
|
56
54
|
timeframe: The time period for top posts. Valid options: 'hour', 'day', 'week', 'month', 'year', 'all' (default: 'day')
|
|
57
55
|
|
|
58
56
|
Returns:
|
|
59
|
-
A
|
|
57
|
+
A dictionary containing a list of top posts with their details, or an error message if the request fails.
|
|
60
58
|
|
|
61
59
|
Raises:
|
|
62
60
|
RequestException: When the HTTP request to the Reddit API fails
|
|
@@ -69,34 +67,29 @@ class RedditApp(APIApplication):
|
|
|
69
67
|
if timeframe not in valid_timeframes:
|
|
70
68
|
return f"Error: Invalid timeframe '{timeframe}'. Please use one of: {', '.join(valid_timeframes)}"
|
|
71
69
|
if not 1 <= limit <= 100:
|
|
72
|
-
return
|
|
73
|
-
f"Error: Invalid limit '{limit}'. Please use a value between 1 and 100."
|
|
74
|
-
)
|
|
70
|
+
return f"Error: Invalid limit '{limit}'. Please use a value between 1 and 100."
|
|
75
71
|
url = f"{self.base_api_url}/r/{subreddit}/top"
|
|
76
72
|
params = {"limit": limit, "t": timeframe}
|
|
77
|
-
logger.info(
|
|
78
|
-
f"Requesting top {limit} posts from r/{subreddit} for timeframe '{timeframe}'"
|
|
79
|
-
)
|
|
73
|
+
logger.info(f"Requesting top {limit} posts from r/{subreddit} for timeframe '{timeframe}'")
|
|
80
74
|
response = self._get(url, params=params)
|
|
81
75
|
return self._handle_response(response)
|
|
82
76
|
|
|
83
|
-
def search_subreddits(
|
|
84
|
-
self, query: str, limit: int = 5, sort: str = "relevance"
|
|
85
|
-
) -> str:
|
|
77
|
+
def search_subreddits(self, query: str, limit: int = 5, sort: str = "relevance") -> dict[str, Any]:
|
|
86
78
|
"""
|
|
87
|
-
|
|
79
|
+
Finds subreddits based on a query string, searching their names and descriptions.
|
|
80
|
+
Results can be sorted by relevance or activity. This function is for discovering communities and does not search for posts or users, unlike the more general `search_reddit` function.
|
|
88
81
|
|
|
89
82
|
Args:
|
|
90
|
-
query: The
|
|
91
|
-
limit: The maximum number of subreddits to return
|
|
92
|
-
sort: The order
|
|
83
|
+
query: The search query for subreddit names and descriptions.
|
|
84
|
+
limit: The maximum number of subreddits to return (1-100, default is 5).
|
|
85
|
+
sort: The sorting order for results. Can be 'relevance' or 'activity' (default is 'relevance').
|
|
93
86
|
|
|
94
87
|
Returns:
|
|
95
|
-
A
|
|
88
|
+
A dictionary containing a list of matching subreddits, including their names, subscriber counts, and descriptions. Returns an error message on failure.
|
|
96
89
|
|
|
97
90
|
Raises:
|
|
98
|
-
RequestException:
|
|
99
|
-
JSONDecodeError:
|
|
91
|
+
RequestException: If the API request to Reddit fails.
|
|
92
|
+
JSONDecodeError: If the API response is not valid JSON.
|
|
100
93
|
|
|
101
94
|
Tags:
|
|
102
95
|
search, important, reddit, api, query, format, list, validation
|
|
@@ -105,18 +98,14 @@ class RedditApp(APIApplication):
|
|
|
105
98
|
if sort not in valid_sorts:
|
|
106
99
|
return f"Error: Invalid sort option '{sort}'. Please use one of: {', '.join(valid_sorts)}"
|
|
107
100
|
if not 1 <= limit <= 100:
|
|
108
|
-
return
|
|
109
|
-
f"Error: Invalid limit '{limit}'. Please use a value between 1 and 100."
|
|
110
|
-
)
|
|
101
|
+
return f"Error: Invalid limit '{limit}'. Please use a value between 1 and 100."
|
|
111
102
|
url = f"{self.base_api_url}/subreddits/search"
|
|
112
103
|
params = {
|
|
113
104
|
"q": query,
|
|
114
105
|
"limit": limit,
|
|
115
106
|
"sort": sort,
|
|
116
107
|
}
|
|
117
|
-
logger.info(
|
|
118
|
-
f"Searching for subreddits matching '{query}' (limit: {limit}, sort: {sort})"
|
|
119
|
-
)
|
|
108
|
+
logger.info(f"Searching for subreddits matching '{query}' (limit: {limit}, sort: {sort})")
|
|
120
109
|
response = self._get(url, params=params)
|
|
121
110
|
return self._handle_response(response)
|
|
122
111
|
|
|
@@ -193,16 +182,10 @@ class RedditApp(APIApplication):
|
|
|
193
182
|
logger.info(f"Submitting a new post to r/{subreddit}")
|
|
194
183
|
response = self._post(url_api, data=data)
|
|
195
184
|
response_json = response.json()
|
|
196
|
-
if
|
|
197
|
-
response_json
|
|
198
|
-
and "json" in response_json
|
|
199
|
-
and "errors" in response_json["json"]
|
|
200
|
-
):
|
|
185
|
+
if response_json and "json" in response_json and "errors" in response_json["json"]:
|
|
201
186
|
errors = response_json["json"]["errors"]
|
|
202
187
|
if errors:
|
|
203
|
-
error_message = ", ".join(
|
|
204
|
-
[f"{code}: {message}" for code, message in errors]
|
|
205
|
-
)
|
|
188
|
+
error_message = ", ".join([f"{code}: {message}" for code, message in errors])
|
|
206
189
|
return f"Reddit API error: {error_message}"
|
|
207
190
|
return response_json
|
|
208
191
|
|
|
@@ -317,7 +300,7 @@ class RedditApp(APIApplication):
|
|
|
317
300
|
Retrieves the full profile information for the currently authenticated user by making a GET request to the `/api/v1/me` Reddit API endpoint. This differs from `get_user_profile`, which requires a username, and `get_current_user_karma`, which specifically fetches karma data.
|
|
318
301
|
|
|
319
302
|
Returns:
|
|
320
|
-
|
|
303
|
+
A dictionary containing the authenticated user's profile information.
|
|
321
304
|
|
|
322
305
|
Tags:
|
|
323
306
|
users
|
|
@@ -333,7 +316,7 @@ class RedditApp(APIApplication):
|
|
|
333
316
|
Fetches the karma breakdown for the authenticated user from the Reddit API. This function specifically targets the `/api/v1/me/karma` endpoint, returning karma statistics per subreddit, which is more specific than `get_current_user_info` that retrieves general profile information.
|
|
334
317
|
|
|
335
318
|
Returns:
|
|
336
|
-
|
|
319
|
+
A dictionary containing the authenticated user's karma breakdown by subreddit.
|
|
337
320
|
|
|
338
321
|
Tags:
|
|
339
322
|
account
|
|
@@ -349,10 +332,10 @@ class RedditApp(APIApplication):
|
|
|
349
332
|
Fetches a specific Reddit post's details and its complete comment tree using the post's unique ID. This function returns the entire discussion, including the original post and all associated comments, providing broader context than `get_comment_by_id` which only retrieves a single comment.
|
|
350
333
|
|
|
351
334
|
Args:
|
|
352
|
-
post_id (
|
|
335
|
+
post_id (str): The Reddit post ID ( e.g. '1m734tx' for https://www.reddit.com/r/mcp/comments/1m734tx/comment/n4occ77/)
|
|
353
336
|
|
|
354
337
|
Returns:
|
|
355
|
-
|
|
338
|
+
A dictionary containing the post details and its comment tree.
|
|
356
339
|
|
|
357
340
|
Tags:
|
|
358
341
|
listings, comments, posts, important
|
|
@@ -384,7 +367,7 @@ class RedditApp(APIApplication):
|
|
|
384
367
|
sr_detail: Optional. Expand subreddit details.
|
|
385
368
|
|
|
386
369
|
Returns:
|
|
387
|
-
|
|
370
|
+
A dictionary containing a listing of controversial posts.
|
|
388
371
|
|
|
389
372
|
Tags:
|
|
390
373
|
listings, posts, controversial, read-only
|
|
@@ -429,7 +412,7 @@ class RedditApp(APIApplication):
|
|
|
429
412
|
sr_detail: Optional. Expand subreddit details.
|
|
430
413
|
|
|
431
414
|
Returns:
|
|
432
|
-
|
|
415
|
+
A dictionary containing a listing of hot posts.
|
|
433
416
|
|
|
434
417
|
Tags:
|
|
435
418
|
listings, posts, hot, read-only
|
|
@@ -473,7 +456,7 @@ class RedditApp(APIApplication):
|
|
|
473
456
|
sr_detail: Optional. Expand subreddit details.
|
|
474
457
|
|
|
475
458
|
Returns:
|
|
476
|
-
|
|
459
|
+
A dictionary containing a listing of new posts.
|
|
477
460
|
|
|
478
461
|
Tags:
|
|
479
462
|
listings, posts, new, read-only
|
|
@@ -520,7 +503,7 @@ class RedditApp(APIApplication):
|
|
|
520
503
|
sr_detail: Optional. Expand subreddit details.
|
|
521
504
|
|
|
522
505
|
Returns:
|
|
523
|
-
|
|
506
|
+
A dictionary containing a listing of hot posts from the specified subreddit.
|
|
524
507
|
|
|
525
508
|
Tags:
|
|
526
509
|
listings, posts, subreddit, hot, read-only
|
|
@@ -568,7 +551,7 @@ class RedditApp(APIApplication):
|
|
|
568
551
|
sr_detail: Optional. Expand subreddit details.
|
|
569
552
|
|
|
570
553
|
Returns:
|
|
571
|
-
|
|
554
|
+
A dictionary containing a listing of new posts from the specified subreddit.
|
|
572
555
|
|
|
573
556
|
Tags:
|
|
574
557
|
listings, posts, subreddit, new, read-only
|
|
@@ -615,7 +598,7 @@ class RedditApp(APIApplication):
|
|
|
615
598
|
sr_detail: Optional. Expand subreddit details.
|
|
616
599
|
|
|
617
600
|
Returns:
|
|
618
|
-
|
|
601
|
+
A dictionary containing a listing of top posts from the specified subreddit.
|
|
619
602
|
|
|
620
603
|
Tags:
|
|
621
604
|
listings, posts, subreddit, top, read-only
|
|
@@ -660,7 +643,7 @@ class RedditApp(APIApplication):
|
|
|
660
643
|
sr_detail: Optional. Expand subreddit details.
|
|
661
644
|
|
|
662
645
|
Returns:
|
|
663
|
-
|
|
646
|
+
A dictionary containing a listing of rising posts.
|
|
664
647
|
|
|
665
648
|
Tags:
|
|
666
649
|
listings, posts, rising, read-only
|
|
@@ -703,7 +686,7 @@ class RedditApp(APIApplication):
|
|
|
703
686
|
sr_detail: Optional. Expand subreddit details.
|
|
704
687
|
|
|
705
688
|
Returns:
|
|
706
|
-
|
|
689
|
+
A dictionary containing a listing of top posts.
|
|
707
690
|
|
|
708
691
|
Tags:
|
|
709
692
|
listings, posts, top, read-only
|
|
@@ -760,7 +743,7 @@ class RedditApp(APIApplication):
|
|
|
760
743
|
type: Optional. A comma-separated list of result types ('sr', 'link', 'user').
|
|
761
744
|
|
|
762
745
|
Returns:
|
|
763
|
-
|
|
746
|
+
A dictionary containing the search results.
|
|
764
747
|
|
|
765
748
|
Tags:
|
|
766
749
|
search, reddit, posts, comments, users, read-only
|
{universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.26.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: universal-mcp-applications
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.26
|
|
4
4
|
Summary: A Universal MCP Application: universal_mcp_applications
|
|
5
5
|
Project-URL: Homepage, https://github.com/universal-mcp/applications
|
|
6
6
|
Project-URL: Repository, https://github.com/universal-mcp/applications
|
{universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.26.dist-info}/RECORD
RENAMED
|
@@ -170,7 +170,7 @@ universal_mcp/applications/openai/__init__.py,sha256=7h2xDZdb1pRh7ZDLtFK9BNDEbRH
|
|
|
170
170
|
universal_mcp/applications/openai/app.py,sha256=5pW85lC5SsojpQNPTZO4QkGkDAcLk8M3nvl1m1Bi0Vk,34123
|
|
171
171
|
universal_mcp/applications/outlook/README.md,sha256=gEdQckOduZHCjLYACZtN3ApFC41y1YdcT0uFCiNvuvk,2830
|
|
172
172
|
universal_mcp/applications/outlook/__init__.py,sha256=yExFpo0apWqcpP7l4qCjAYwMyzomUaEeNDhY7Gi-We0,28
|
|
173
|
-
universal_mcp/applications/outlook/app.py,sha256=
|
|
173
|
+
universal_mcp/applications/outlook/app.py,sha256=3LvFRBKzlA_Gzkj07eyFiuCcKRBTd7-9WIhdrYpLOO8,20885
|
|
174
174
|
universal_mcp/applications/perplexity/README.md,sha256=3DTRkkaGKmAyZz3Rpdo5OUyEXogWqzZ228gxrixO2pI,554
|
|
175
175
|
universal_mcp/applications/perplexity/__init__.py,sha256=f4uz8qlw-uek6AlyWxoWxukubaHb6YV4riTcvQhfvO0,31
|
|
176
176
|
universal_mcp/applications/perplexity/app.py,sha256=M47xUTRJbnd7zDxVG1R3nkX46aI7GZ-aVPphNQjMkvA,2815
|
|
@@ -182,7 +182,7 @@ universal_mcp/applications/posthog/__init__.py,sha256=2j8vH09Xqz51BlfNehaEvY2A2L
|
|
|
182
182
|
universal_mcp/applications/posthog/app.py,sha256=-T0hOSxPT3qQEVG8IrRY0MVi0YI8yHHeKPgl5jRexGY,275182
|
|
183
183
|
universal_mcp/applications/reddit/README.md,sha256=RzGOX8sFJldmLsrjFG1FHmWzL7RddZTylb-m8XjSKQI,6558
|
|
184
184
|
universal_mcp/applications/reddit/__init__.py,sha256=JHA_BMVnuQyoDMbQt5dRNxKPrAxyZZL6zzQyNbvyjHs,27
|
|
185
|
-
universal_mcp/applications/reddit/app.py,sha256=
|
|
185
|
+
universal_mcp/applications/reddit/app.py,sha256=HUqYRJ7U07uMg-U5c5VDrboSlSSB1_gD_dtDiwqDSDo,35648
|
|
186
186
|
universal_mcp/applications/resend/README.md,sha256=zfKzut3KCw9JlX3crspSjRsLZyoN9uly_yZWjWA4LUU,8409
|
|
187
187
|
universal_mcp/applications/resend/__init__.py,sha256=4me7YQFrYTNvqbJawBrsrJlzyFRwXZA6u4E09IPWjlk,27
|
|
188
188
|
universal_mcp/applications/resend/app.py,sha256=bPW5wgl7wf2m4tgygSwdfRCaKKBEPwMrLWm3yhOP9kk,34879
|
|
@@ -276,7 +276,7 @@ universal_mcp/applications/youtube/app.py,sha256=eqgqe0b53W9Mj0FZGW3ZqY3xkGF4NbO
|
|
|
276
276
|
universal_mcp/applications/zenquotes/README.md,sha256=FJyoTGRCaZjF_bsCBqg1CrYcvIfuUG_Qk616G1wjhF8,512
|
|
277
277
|
universal_mcp/applications/zenquotes/__init__.py,sha256=C5nEHZ3Xy6nYUarq0BqQbbJnHs0UtSlqhk0DqmvWiHk,58
|
|
278
278
|
universal_mcp/applications/zenquotes/app.py,sha256=7xIEnSZWAGYu5583Be2ZjSCtLUAfMWRzucSpp7hw_h4,1299
|
|
279
|
-
universal_mcp_applications-0.1.
|
|
280
|
-
universal_mcp_applications-0.1.
|
|
281
|
-
universal_mcp_applications-0.1.
|
|
282
|
-
universal_mcp_applications-0.1.
|
|
279
|
+
universal_mcp_applications-0.1.26.dist-info/METADATA,sha256=0Ae_g0zJq4xSsdekTvbRe5hTweEP3hMBVXMTYiDrmmM,2956
|
|
280
|
+
universal_mcp_applications-0.1.26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
281
|
+
universal_mcp_applications-0.1.26.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
|
|
282
|
+
universal_mcp_applications-0.1.26.dist-info/RECORD,,
|
{universal_mcp_applications-0.1.25.dist-info → universal_mcp_applications-0.1.26.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|