universal-mcp 0.1.8rc2__py3-none-any.whl → 0.1.8rc4__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.
- universal_mcp/__init__.py +0 -2
- universal_mcp/analytics.py +75 -0
- universal_mcp/applications/ahrefs/README.md +76 -0
- universal_mcp/applications/ahrefs/__init__.py +0 -0
- universal_mcp/applications/ahrefs/app.py +2291 -0
- universal_mcp/applications/application.py +94 -5
- universal_mcp/applications/calendly/app.py +412 -171
- universal_mcp/applications/coda/README.md +133 -0
- universal_mcp/applications/coda/__init__.py +0 -0
- universal_mcp/applications/coda/app.py +3671 -0
- universal_mcp/applications/e2b/app.py +8 -35
- universal_mcp/applications/figma/README.md +74 -0
- universal_mcp/applications/figma/__init__.py +0 -0
- universal_mcp/applications/figma/app.py +1261 -0
- universal_mcp/applications/firecrawl/app.py +3 -33
- universal_mcp/applications/github/app.py +41 -42
- universal_mcp/applications/google_calendar/app.py +20 -31
- universal_mcp/applications/google_docs/app.py +21 -46
- universal_mcp/applications/google_drive/app.py +53 -76
- universal_mcp/applications/google_mail/app.py +40 -56
- universal_mcp/applications/google_sheet/app.py +43 -68
- universal_mcp/applications/markitdown/app.py +4 -4
- universal_mcp/applications/notion/app.py +93 -83
- universal_mcp/applications/perplexity/app.py +4 -38
- universal_mcp/applications/reddit/app.py +32 -32
- universal_mcp/applications/resend/app.py +4 -22
- universal_mcp/applications/serpapi/app.py +6 -32
- universal_mcp/applications/tavily/app.py +4 -24
- universal_mcp/applications/wrike/app.py +565 -237
- universal_mcp/applications/youtube/app.py +625 -183
- universal_mcp/applications/zenquotes/app.py +3 -3
- universal_mcp/exceptions.py +1 -0
- universal_mcp/integrations/__init__.py +11 -2
- universal_mcp/integrations/agentr.py +27 -4
- universal_mcp/integrations/integration.py +14 -6
- universal_mcp/logger.py +3 -56
- universal_mcp/servers/__init__.py +2 -1
- universal_mcp/servers/server.py +73 -77
- universal_mcp/stores/store.py +5 -3
- universal_mcp/tools/__init__.py +1 -1
- universal_mcp/tools/adapters.py +4 -1
- universal_mcp/tools/func_metadata.py +5 -6
- universal_mcp/tools/tools.py +108 -51
- universal_mcp/utils/docgen.py +121 -69
- universal_mcp/utils/docstring_parser.py +44 -21
- universal_mcp/utils/dump_app_tools.py +33 -23
- universal_mcp/utils/installation.py +199 -8
- universal_mcp/utils/openapi.py +121 -47
- {universal_mcp-0.1.8rc2.dist-info → universal_mcp-0.1.8rc4.dist-info}/METADATA +2 -2
- universal_mcp-0.1.8rc4.dist-info/RECORD +81 -0
- universal_mcp-0.1.8rc2.dist-info/RECORD +0 -71
- {universal_mcp-0.1.8rc2.dist-info → universal_mcp-0.1.8rc4.dist-info}/WHEEL +0 -0
- {universal_mcp-0.1.8rc2.dist-info → universal_mcp-0.1.8rc4.dist-info}/entry_points.txt +0 -0
@@ -15,41 +15,11 @@ class FirecrawlApp(APIApplication):
|
|
15
15
|
|
16
16
|
def __init__(self, integration: Integration | None = None) -> None:
|
17
17
|
super().__init__(name="firecrawl", integration=integration)
|
18
|
-
self.api_key: str | None = None
|
19
|
-
|
20
|
-
def _set_api_key(self):
|
21
|
-
"""
|
22
|
-
Ensures the API key is loaded from the integration.
|
23
|
-
Raises ValueError if the integration or key is missing/misconfigured.
|
24
|
-
"""
|
25
|
-
if self.api_key:
|
26
|
-
return
|
27
|
-
|
28
|
-
if not self.integration:
|
29
|
-
raise ValueError("Integration is None. Cannot retrieve Firecrawl API Key.")
|
30
|
-
|
31
|
-
credentials = self.integration.get_credentials()
|
32
|
-
if not credentials:
|
33
|
-
raise ValueError(
|
34
|
-
f"Failed to retrieve Firecrawl API Key using integration '{self.integration.name}'. "
|
35
|
-
f"Check store configuration (e.g., ensure the correct source like environment variable is set)."
|
36
|
-
)
|
37
|
-
api_key = (
|
38
|
-
credentials.get("api_key")
|
39
|
-
or credentials.get("API_KEY")
|
40
|
-
or credentials.get("apiKey")
|
41
|
-
)
|
42
|
-
if not api_key:
|
43
|
-
raise ValueError(
|
44
|
-
f"Failed to retrieve Firecrawl API Key using integration '{self.integration.name}'. "
|
45
|
-
f"Check store configuration (e.g., ensure the correct environment variable is set)."
|
46
|
-
)
|
47
|
-
self.api_key = api_key
|
48
18
|
|
49
19
|
def _get_client(self) -> FirecrawlApiClient:
|
50
20
|
"""Initializes and returns the Firecrawl client after ensuring API key is set."""
|
51
|
-
self.
|
52
|
-
return FirecrawlApiClient(api_key=
|
21
|
+
api_key = self.integration.get_credentials().get("api_key")
|
22
|
+
return FirecrawlApiClient(api_key=api_key)
|
53
23
|
|
54
24
|
def scrape_url(
|
55
25
|
self, url: str, params: dict[str, Any] | None = None
|
@@ -295,4 +265,4 @@ class FirecrawlApp(APIApplication):
|
|
295
265
|
self.check_batch_scrape_status,
|
296
266
|
self.start_extract,
|
297
267
|
self.check_extract_status,
|
298
|
-
]
|
268
|
+
]
|
@@ -7,7 +7,6 @@ from universal_mcp.integrations import Integration
|
|
7
7
|
|
8
8
|
|
9
9
|
class GithubApp(APIApplication):
|
10
|
-
|
11
10
|
APP_TAGS: ClassVar[list[str]] = ["developers-tools"]
|
12
11
|
|
13
12
|
def __init__(self, integration: Integration) -> None:
|
@@ -28,17 +27,17 @@ class GithubApp(APIApplication):
|
|
28
27
|
def star_repository(self, repo_full_name: str) -> str:
|
29
28
|
"""
|
30
29
|
Stars a GitHub repository using the GitHub API and returns a status message.
|
31
|
-
|
30
|
+
|
32
31
|
Args:
|
33
32
|
repo_full_name: The full name of the repository in 'owner/repo' format (e.g., 'octocat/Hello-World')
|
34
|
-
|
33
|
+
|
35
34
|
Returns:
|
36
35
|
A string message indicating whether the starring operation was successful, the repository was not found, or an error occurred
|
37
|
-
|
36
|
+
|
38
37
|
Raises:
|
39
38
|
RequestException: If there are network connectivity issues or API request failures
|
40
39
|
ValueError: If the repository name format is invalid
|
41
|
-
|
40
|
+
|
42
41
|
Tags:
|
43
42
|
star, github, api, action, social, repository, important
|
44
43
|
"""
|
@@ -55,17 +54,17 @@ class GithubApp(APIApplication):
|
|
55
54
|
def list_commits(self, repo_full_name: str) -> str:
|
56
55
|
"""
|
57
56
|
Retrieves and formats a list of recent commits from a GitHub repository
|
58
|
-
|
57
|
+
|
59
58
|
Args:
|
60
59
|
repo_full_name: The full name of the repository in 'owner/repo' format
|
61
|
-
|
60
|
+
|
62
61
|
Returns:
|
63
62
|
A formatted string containing the most recent 12 commits, including commit hash, message, and author
|
64
|
-
|
63
|
+
|
65
64
|
Raises:
|
66
65
|
requests.exceptions.HTTPError: When the GitHub API request fails (e.g., repository not found, rate limit exceeded)
|
67
66
|
requests.exceptions.RequestException: When network issues or other request-related problems occur
|
68
|
-
|
67
|
+
|
69
68
|
Tags:
|
70
69
|
list, read, commits, github, history, api, important
|
71
70
|
"""
|
@@ -88,17 +87,17 @@ class GithubApp(APIApplication):
|
|
88
87
|
def list_branches(self, repo_full_name: str) -> str:
|
89
88
|
"""
|
90
89
|
Lists all branches for a specified GitHub repository and returns them in a formatted string representation.
|
91
|
-
|
90
|
+
|
92
91
|
Args:
|
93
92
|
repo_full_name: The full name of the repository in 'owner/repo' format (e.g., 'octocat/Hello-World')
|
94
|
-
|
93
|
+
|
95
94
|
Returns:
|
96
95
|
A formatted string containing the list of branches, or a message indicating no branches were found
|
97
|
-
|
96
|
+
|
98
97
|
Raises:
|
99
98
|
HTTPError: When the GitHub API request fails (e.g., repository not found, authentication error)
|
100
99
|
RequestException: When there are network connectivity issues or API communication problems
|
101
|
-
|
100
|
+
|
102
101
|
Tags:
|
103
102
|
list, branches, github, read, api, repository, important
|
104
103
|
"""
|
@@ -118,17 +117,17 @@ class GithubApp(APIApplication):
|
|
118
117
|
def list_pull_requests(self, repo_full_name: str, state: str = "open") -> str:
|
119
118
|
"""
|
120
119
|
Retrieves and formats a list of pull requests for a specified GitHub repository.
|
121
|
-
|
120
|
+
|
122
121
|
Args:
|
123
122
|
repo_full_name: The full name of the repository in the format 'owner/repo' (e.g., 'tensorflow/tensorflow')
|
124
123
|
state: Filter for pull request state. Can be 'open', 'closed', or 'all'. Defaults to 'open'
|
125
|
-
|
124
|
+
|
126
125
|
Returns:
|
127
126
|
A formatted string containing the list of pull requests, including PR number, title, author, and status. Returns a message if no pull requests are found.
|
128
|
-
|
127
|
+
|
129
128
|
Raises:
|
130
129
|
HTTPError: Raised when the GitHub API request fails (e.g., invalid repository name, rate limiting, or authentication issues)
|
131
|
-
|
130
|
+
|
132
131
|
Tags:
|
133
132
|
list, pull-request, github, api, read, important, fetch, query
|
134
133
|
"""
|
@@ -163,7 +162,7 @@ class GithubApp(APIApplication):
|
|
163
162
|
) -> list[dict[str, Any]]:
|
164
163
|
"""
|
165
164
|
Retrieves a list of issues from a specified GitHub repository with optional filtering parameters.
|
166
|
-
|
165
|
+
|
167
166
|
Args:
|
168
167
|
repo_full_name: The full name of the repository in 'owner/repo' format
|
169
168
|
state: Filter issues by state ('open', 'closed', 'all'). Defaults to 'open'
|
@@ -171,14 +170,14 @@ class GithubApp(APIApplication):
|
|
171
170
|
labels: Comma-separated string of label names to filter by (e.g., 'bug,ui,@high')
|
172
171
|
per_page: Number of results per page (max 100). Defaults to 30
|
173
172
|
page: Page number for pagination. Defaults to 1
|
174
|
-
|
173
|
+
|
175
174
|
Returns:
|
176
175
|
List of dictionaries containing issue data from the GitHub API response
|
177
|
-
|
176
|
+
|
178
177
|
Raises:
|
179
178
|
HTTPError: When the GitHub API request fails (e.g., invalid repository name, authentication failure)
|
180
179
|
RequestException: When there are network connectivity issues or other request-related problems
|
181
|
-
|
180
|
+
|
182
181
|
Tags:
|
183
182
|
list, issues, github, api, read, filter, pagination, important, project-management
|
184
183
|
"""
|
@@ -196,18 +195,18 @@ class GithubApp(APIApplication):
|
|
196
195
|
def get_pull_request(self, repo_full_name: str, pull_number: int) -> str:
|
197
196
|
"""
|
198
197
|
Retrieves and formats detailed information about a specific GitHub pull request from a repository
|
199
|
-
|
198
|
+
|
200
199
|
Args:
|
201
200
|
repo_full_name: The full repository name in 'owner/repo' format (e.g., 'octocat/Hello-World')
|
202
201
|
pull_number: The numeric identifier of the pull request to retrieve
|
203
|
-
|
202
|
+
|
204
203
|
Returns:
|
205
204
|
A formatted string containing pull request details including title, creator, status, and description
|
206
|
-
|
205
|
+
|
207
206
|
Raises:
|
208
207
|
HTTPError: Raised when the GitHub API request fails (e.g., invalid repository name, non-existent PR number, or authentication issues)
|
209
208
|
RequestException: Raised when there are network connectivity issues or other request-related problems
|
210
|
-
|
209
|
+
|
211
210
|
Tags:
|
212
211
|
get, read, github, pull-request, api, fetch, format, important
|
213
212
|
"""
|
@@ -242,7 +241,7 @@ class GithubApp(APIApplication):
|
|
242
241
|
) -> dict[str, Any]:
|
243
242
|
"""
|
244
243
|
Creates a new pull request in a GitHub repository, optionally converting an existing issue into a pull request.
|
245
|
-
|
244
|
+
|
246
245
|
Args:
|
247
246
|
repo_full_name: The full name of the repository (e.g. 'owner/repo')
|
248
247
|
head: The name of the branch where your changes are implemented
|
@@ -252,14 +251,14 @@ class GithubApp(APIApplication):
|
|
252
251
|
issue: An issue number to convert to a pull request. If specified, the issue's title, body, and comments will be used
|
253
252
|
maintainer_can_modify: Indicates whether maintainers can modify the pull request
|
254
253
|
draft: Indicates whether the pull request is a draft
|
255
|
-
|
254
|
+
|
256
255
|
Returns:
|
257
256
|
A dictionary containing the complete GitHub API response
|
258
|
-
|
257
|
+
|
259
258
|
Raises:
|
260
259
|
ValueError: Raised when neither 'title' nor 'issue' parameter is specified
|
261
260
|
HTTPError: Raised when the GitHub API request fails
|
262
|
-
|
261
|
+
|
263
262
|
Tags:
|
264
263
|
create, pull-request, github, api, write, important
|
265
264
|
"""
|
@@ -288,19 +287,19 @@ class GithubApp(APIApplication):
|
|
288
287
|
) -> str:
|
289
288
|
"""
|
290
289
|
Creates a new issue in a specified GitHub repository with a title, body content, and optional labels.
|
291
|
-
|
290
|
+
|
292
291
|
Args:
|
293
292
|
repo_full_name: The full name of the repository in 'owner/repo' format
|
294
293
|
title: The title of the issue
|
295
294
|
body: The contents/description of the issue (defaults to empty string)
|
296
295
|
labels: Labels to associate with the issue, as a comma-separated string or list. Only users with push access can set labels
|
297
|
-
|
296
|
+
|
298
297
|
Returns:
|
299
298
|
A string containing a confirmation message with the issue number, title, and URL
|
300
|
-
|
299
|
+
|
301
300
|
Raises:
|
302
301
|
HTTPError: When the GitHub API request fails (e.g., invalid repository name, authentication issues, or insufficient permissions)
|
303
|
-
|
302
|
+
|
304
303
|
Tags:
|
305
304
|
create, issues, github, api, project-management, write, important
|
306
305
|
"""
|
@@ -331,19 +330,19 @@ class GithubApp(APIApplication):
|
|
331
330
|
) -> str:
|
332
331
|
"""
|
333
332
|
Retrieves and formats a list of activities for a specified GitHub repository.
|
334
|
-
|
333
|
+
|
335
334
|
Args:
|
336
335
|
repo_full_name: The full name of the repository in 'owner/repo' format
|
337
336
|
direction: The sort direction for results ('asc' or 'desc'). Defaults to 'desc'
|
338
337
|
per_page: Number of activities to return per page (1-100). Defaults to 30
|
339
|
-
|
338
|
+
|
340
339
|
Returns:
|
341
340
|
A formatted string containing a list of repository activities, including timestamps and actor names. Returns a 'No activities' message if no activities are found.
|
342
|
-
|
341
|
+
|
343
342
|
Raises:
|
344
343
|
HTTPError: Raised when the GitHub API request fails
|
345
344
|
ValueError: May be raised if repo_full_name is invalid or empty after stripping
|
346
|
-
|
345
|
+
|
347
346
|
Tags:
|
348
347
|
list, activity, github, read, events, api, query, format
|
349
348
|
"""
|
@@ -379,7 +378,7 @@ class GithubApp(APIApplication):
|
|
379
378
|
) -> dict[str, Any]:
|
380
379
|
"""
|
381
380
|
Updates an existing GitHub issue with specified parameters including title, body, assignee, state, and state reason.
|
382
|
-
|
381
|
+
|
383
382
|
Args:
|
384
383
|
repo_full_name: The full name of the repository in 'owner/repo' format
|
385
384
|
issue_number: The unique identifier number of the issue to update
|
@@ -388,14 +387,14 @@ class GithubApp(APIApplication):
|
|
388
387
|
assignee: GitHub username to assign to the issue (optional)
|
389
388
|
state: The desired state of the issue ('open' or 'closed') (optional)
|
390
389
|
state_reason: The reason for state change ('completed', 'not_planned', 'reopened', or null) (optional)
|
391
|
-
|
390
|
+
|
392
391
|
Returns:
|
393
392
|
A dictionary containing the complete GitHub API response with updated issue details
|
394
|
-
|
393
|
+
|
395
394
|
Raises:
|
396
395
|
HTTPError: Raised when the GitHub API request fails (e.g., invalid repository, non-existent issue, insufficient permissions)
|
397
396
|
RequestException: Raised when there's a network error or API connectivity issue
|
398
|
-
|
397
|
+
|
399
398
|
Tags:
|
400
399
|
github, issues, update, api, project-management, write, important
|
401
400
|
"""
|
@@ -427,4 +426,4 @@ class GithubApp(APIApplication):
|
|
427
426
|
self.create_issue,
|
428
427
|
self.update_issue,
|
429
428
|
self.list_repo_activities,
|
430
|
-
]
|
429
|
+
]
|
@@ -11,17 +11,6 @@ class GoogleCalendarApp(APIApplication):
|
|
11
11
|
super().__init__(name="google-calendar", integration=integration)
|
12
12
|
self.base_api_url = "https://www.googleapis.com/calendar/v3/calendars/primary"
|
13
13
|
|
14
|
-
def _get_headers(self):
|
15
|
-
if not self.integration:
|
16
|
-
raise ValueError("Integration not configured for GoogleCalendarApp")
|
17
|
-
credentials = self.integration.get_credentials()
|
18
|
-
if "headers" in credentials:
|
19
|
-
return credentials["headers"]
|
20
|
-
return {
|
21
|
-
"Authorization": f"Bearer {credentials['access_token']}",
|
22
|
-
"Accept": "application/json",
|
23
|
-
}
|
24
|
-
|
25
14
|
def _format_datetime(self, dt_string: str) -> str:
|
26
15
|
"""Format a datetime string from ISO format to a human-readable format.
|
27
16
|
|
@@ -61,18 +50,18 @@ class GoogleCalendarApp(APIApplication):
|
|
61
50
|
) -> str:
|
62
51
|
"""
|
63
52
|
Retrieves and formats events from Google Calendar for today or a specified number of future days, with optional result limiting and timezone specification.
|
64
|
-
|
53
|
+
|
65
54
|
Args:
|
66
55
|
days: Number of days to retrieve events for (default: 1, which is just today)
|
67
56
|
max_results: Maximum number of events to return (optional)
|
68
57
|
time_zone: Time zone used in the response (optional, default is calendar's time zone)
|
69
|
-
|
58
|
+
|
70
59
|
Returns:
|
71
60
|
A formatted string containing a list of calendar events with their times and IDs, or a message indicating no events were found
|
72
|
-
|
61
|
+
|
73
62
|
Raises:
|
74
63
|
HTTPError: Raised when the API request fails or returns an error status code
|
75
|
-
|
64
|
+
|
76
65
|
Tags:
|
77
66
|
fetch, list, calendar, events, date-time, important, api, formatting
|
78
67
|
"""
|
@@ -139,19 +128,19 @@ class GoogleCalendarApp(APIApplication):
|
|
139
128
|
) -> str:
|
140
129
|
"""
|
141
130
|
Retrieves and formats detailed information about a specific Google Calendar event by its ID
|
142
|
-
|
131
|
+
|
143
132
|
Args:
|
144
133
|
event_id: The unique identifier of the calendar event to retrieve
|
145
134
|
max_attendees: Optional. The maximum number of attendees to include in the response. If None, includes all attendees
|
146
135
|
time_zone: Optional. The time zone to use for formatting dates in the response. If None, uses the calendar's default time zone
|
147
|
-
|
136
|
+
|
148
137
|
Returns:
|
149
138
|
A formatted string containing comprehensive event details including summary, time, location, description, creator, organizer, recurrence status, and attendee information
|
150
|
-
|
139
|
+
|
151
140
|
Raises:
|
152
141
|
HTTPError: Raised when the API request fails or returns an error status code
|
153
142
|
JSONDecodeError: Raised when the API response cannot be parsed as JSON
|
154
|
-
|
143
|
+
|
155
144
|
Tags:
|
156
145
|
retrieve, calendar, event, format, api, important
|
157
146
|
"""
|
@@ -219,7 +208,7 @@ class GoogleCalendarApp(APIApplication):
|
|
219
208
|
) -> str:
|
220
209
|
"""
|
221
210
|
Retrieves and formats a list of events from Google Calendar with customizable filtering, sorting, and pagination options
|
222
|
-
|
211
|
+
|
223
212
|
Args:
|
224
213
|
max_results: Maximum number of events to return (default: 10, max: 2500)
|
225
214
|
time_min: Start time in ISO format (e.g., '2023-12-01T00:00:00Z'). Defaults to current time if not specified
|
@@ -229,13 +218,13 @@ class GoogleCalendarApp(APIApplication):
|
|
229
218
|
single_events: Whether to expand recurring events into individual instances (default: True)
|
230
219
|
time_zone: Time zone for response formatting (defaults to calendar's time zone)
|
231
220
|
page_token: Token for retrieving a specific page of results in paginated responses
|
232
|
-
|
221
|
+
|
233
222
|
Returns:
|
234
223
|
A formatted string containing the list of events with details including summary, ID, start time, and location, or a message if no events are found
|
235
|
-
|
224
|
+
|
236
225
|
Raises:
|
237
226
|
HTTPError: Raised when the API request fails or returns an error status code
|
238
|
-
|
227
|
+
|
239
228
|
Tags:
|
240
229
|
list, calendar, events, search, filter, pagination, format, important
|
241
230
|
"""
|
@@ -307,17 +296,17 @@ class GoogleCalendarApp(APIApplication):
|
|
307
296
|
def quick_add_event(self, text: str, send_updates: str = "none") -> str:
|
308
297
|
"""
|
309
298
|
Creates a calendar event using natural language text input and returns a formatted confirmation message with event details.
|
310
|
-
|
299
|
+
|
311
300
|
Args:
|
312
301
|
text: Natural language text describing the event (e.g., 'Meeting with John at Coffee Shop tomorrow 3pm-4pm')
|
313
302
|
send_updates: Specifies who should receive event notifications: 'all', 'externalOnly', or 'none' (default)
|
314
|
-
|
303
|
+
|
315
304
|
Returns:
|
316
305
|
A formatted string containing the confirmation message with event details including summary, time, location, and event ID
|
317
|
-
|
306
|
+
|
318
307
|
Raises:
|
319
308
|
HTTPError: Raised when the API request fails or returns an error status code
|
320
|
-
|
309
|
+
|
321
310
|
Tags:
|
322
311
|
create, calendar, event, quick-add, natural-language, important
|
323
312
|
"""
|
@@ -358,7 +347,7 @@ class GoogleCalendarApp(APIApplication):
|
|
358
347
|
) -> str:
|
359
348
|
"""
|
360
349
|
Retrieves and formats all instances of a recurring calendar event within a specified time range, showing details like time, status, and modifications for each occurrence.
|
361
|
-
|
350
|
+
|
362
351
|
Args:
|
363
352
|
event_id: ID of the recurring event
|
364
353
|
max_results: Maximum number of event instances to return (default: 25, max: 2500)
|
@@ -367,14 +356,14 @@ class GoogleCalendarApp(APIApplication):
|
|
367
356
|
time_zone: Time zone used in the response (defaults to calendar's time zone)
|
368
357
|
show_deleted: Whether to include deleted instances (default: False)
|
369
358
|
page_token: Token for retrieving a specific page of results
|
370
|
-
|
359
|
+
|
371
360
|
Returns:
|
372
361
|
A formatted string containing a list of event instances with details including time, status, instance ID, and modification information, plus pagination token if applicable.
|
373
|
-
|
362
|
+
|
374
363
|
Raises:
|
375
364
|
HTTPError: Raised when the API request fails or returns an error status code
|
376
365
|
JSONDecodeError: Raised when the API response cannot be parsed as JSON
|
377
|
-
|
366
|
+
|
378
367
|
Tags:
|
379
368
|
list, retrieve, calendar, events, recurring, pagination, formatting, important
|
380
369
|
"""
|
@@ -1,9 +1,6 @@
|
|
1
1
|
from typing import Any
|
2
2
|
|
3
|
-
from loguru import logger
|
4
|
-
|
5
3
|
from universal_mcp.applications.application import APIApplication
|
6
|
-
from universal_mcp.exceptions import NotAuthorizedError
|
7
4
|
from universal_mcp.integrations import Integration
|
8
5
|
|
9
6
|
|
@@ -11,36 +8,21 @@ class GoogleDocsApp(APIApplication):
|
|
11
8
|
def __init__(self, integration: Integration) -> None:
|
12
9
|
super().__init__(name="google-docs", integration=integration)
|
13
10
|
self.base_api_url = "https://docs.googleapis.com/v1/documents"
|
14
|
-
|
15
|
-
def _get_headers(self):
|
16
|
-
if not self.integration:
|
17
|
-
raise ValueError("Integration not configured for GoogleDocsApp")
|
18
|
-
credentials = self.integration.get_credentials()
|
19
|
-
if not credentials:
|
20
|
-
logger.warning("No Google credentials found via integration.")
|
21
|
-
action = self.integration.authorize()
|
22
|
-
raise NotAuthorizedError(action)
|
23
|
-
if "headers" in credentials:
|
24
|
-
return credentials["headers"]
|
25
|
-
return {
|
26
|
-
"Authorization": f"Bearer {credentials['access_token']}",
|
27
|
-
"Content-Type": "application/json",
|
28
|
-
}
|
29
|
-
|
11
|
+
|
30
12
|
def create_document(self, title: str) -> dict[str, Any]:
|
31
13
|
"""
|
32
14
|
Creates a new blank Google Document with the specified title and returns the API response.
|
33
|
-
|
15
|
+
|
34
16
|
Args:
|
35
17
|
title: The title for the new Google Document to be created
|
36
|
-
|
18
|
+
|
37
19
|
Returns:
|
38
20
|
A dictionary containing the Google Docs API response with document details and metadata
|
39
|
-
|
21
|
+
|
40
22
|
Raises:
|
41
23
|
HTTPError: If the API request fails due to network issues, authentication errors, or invalid parameters
|
42
24
|
RequestException: If there are connection errors or timeout issues during the API request
|
43
|
-
|
25
|
+
|
44
26
|
Tags:
|
45
27
|
create, document, api, important, google-docs, http
|
46
28
|
"""
|
@@ -49,65 +31,58 @@ class GoogleDocsApp(APIApplication):
|
|
49
31
|
response = self._post(url, data=document_data)
|
50
32
|
response.raise_for_status()
|
51
33
|
return response.json()
|
52
|
-
|
34
|
+
|
53
35
|
def get_document(self, document_id: str) -> dict[str, Any]:
|
54
36
|
"""
|
55
37
|
Retrieves the latest version of a specified document from the Google Docs API.
|
56
|
-
|
38
|
+
|
57
39
|
Args:
|
58
40
|
document_id: The unique identifier of the document to retrieve
|
59
|
-
|
41
|
+
|
60
42
|
Returns:
|
61
43
|
A dictionary containing the document data from the Google Docs API response
|
62
|
-
|
44
|
+
|
63
45
|
Raises:
|
64
46
|
HTTPError: If the API request fails or the document is not found
|
65
47
|
JSONDecodeError: If the API response cannot be parsed as JSON
|
66
|
-
|
48
|
+
|
67
49
|
Tags:
|
68
50
|
retrieve, read, api, document, google-docs, important
|
69
51
|
"""
|
70
52
|
url = f"{self.base_api_url}/{document_id}"
|
71
53
|
response = self._get(url)
|
72
54
|
return response.json()
|
73
|
-
|
74
|
-
def add_content(
|
55
|
+
|
56
|
+
def add_content(
|
57
|
+
self, document_id: str, content: str, index: int = 1
|
58
|
+
) -> dict[str, Any]:
|
75
59
|
"""
|
76
60
|
Adds text content at a specified position in an existing Google Document via the Google Docs API.
|
77
|
-
|
61
|
+
|
78
62
|
Args:
|
79
63
|
document_id: The unique identifier of the Google Document to be updated
|
80
64
|
content: The text content to be inserted into the document
|
81
65
|
index: The zero-based position in the document where the text should be inserted (default: 1)
|
82
|
-
|
66
|
+
|
83
67
|
Returns:
|
84
68
|
A dictionary containing the Google Docs API response after performing the batch update operation
|
85
|
-
|
69
|
+
|
86
70
|
Raises:
|
87
71
|
HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
|
88
72
|
RequestException: When there are network connectivity issues or API endpoint problems
|
89
|
-
|
73
|
+
|
90
74
|
Tags:
|
91
75
|
update, insert, document, api, google-docs, batch, content-management, important
|
92
76
|
"""
|
93
77
|
url = f"{self.base_api_url}/{document_id}:batchUpdate"
|
94
78
|
batch_update_data = {
|
95
79
|
"requests": [
|
96
|
-
{
|
97
|
-
"insertText": {
|
98
|
-
"location": {"index": index},
|
99
|
-
"text": content
|
100
|
-
}
|
101
|
-
}
|
80
|
+
{"insertText": {"location": {"index": index}, "text": content}}
|
102
81
|
]
|
103
82
|
}
|
104
83
|
response = self._post(url, data=batch_update_data)
|
105
84
|
response.raise_for_status()
|
106
85
|
return response.json()
|
107
|
-
|
86
|
+
|
108
87
|
def list_tools(self):
|
109
|
-
return [
|
110
|
-
self.create_document,
|
111
|
-
self.get_document,
|
112
|
-
self.add_content
|
113
|
-
]
|
88
|
+
return [self.create_document, self.get_document, self.add_content]
|