universal-mcp-applications 0.1.8__py3-none-any.whl → 0.1.9__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.

@@ -1,3 +1,4 @@
1
+ import os
1
2
  from typing import Annotated, Any
2
3
 
3
4
  from loguru import logger
@@ -25,7 +26,7 @@ class E2bApp(APIApplication):
25
26
 
26
27
  def __init__(self, integration: Integration | None = None, **kwargs: Any) -> None:
27
28
  super().__init__(name="e2b", integration=integration, **kwargs)
28
- self._e2b_api_key: str | None = None # Cache for the API key
29
+ self._e2b_api_key: str | None = None
29
30
  if Sandbox is None:
30
31
  logger.warning(
31
32
  "E2B Sandbox SDK is not available. E2B tools will not function."
@@ -136,48 +137,29 @@ class E2bApp(APIApplication):
136
137
  execute, sandbox, code-execution, security, important
137
138
  """
138
139
  if Sandbox is None:
139
- logger.error(
140
- "E2B Sandbox SDK is not available. Cannot execute_python_code."
141
- )
142
- raise ToolError(
143
- "E2B Sandbox SDK (e2b_code_interpreter) is not installed or failed to import."
144
- )
145
-
140
+ raise ToolError("E2B Sandbox SDK (e2b_code_interpreter) is not installed.")
146
141
  if not code or not isinstance(code, str):
147
142
  raise ValueError("Provided code must be a non-empty string.")
148
143
 
149
- logger.info("Attempting to execute Python code in E2B Sandbox.")
150
144
  try:
151
- current_api_key = self.e2b_api_key
152
-
153
- with Sandbox(api_key=current_api_key) as sandbox:
154
- logger.info(
155
- f"E2B Sandbox (ID: {sandbox.sandbox_id}) initialized. Running code."
156
- )
157
- execution = sandbox.run_code(
158
- code=code
159
- ) # run_python is the method in e2b-code-interpreter
160
- result = self._format_execution_output(
161
- execution.logs
162
- ) # execution_result directly has logs
145
+ logger.info("Attempting to execute Python code in E2B Sandbox.")
146
+ os.environ["E2B_API_KEY"] = self.e2b_api_key
147
+ with Sandbox.create() as sandbox:
148
+ logger.info("E2B Sandbox initialized. Running code.")
149
+ execution = sandbox.run_code(code)
150
+ result = self._format_execution_output(execution)
163
151
  logger.info("E2B code execution successful.")
164
152
  return result
165
- except NotAuthorizedError: # Re-raise if caught from self.e2b_api_key
166
- raise
167
153
  except Exception as e:
154
+ logger.exception("E2B code execution failed.")
155
+ lower = str(e).lower()
168
156
  if (
169
- "authentication" in str(e).lower()
170
- or "api key" in str(e).lower()
171
- or "401" in str(e)
172
- or "unauthorized" in str(e).lower()
157
+ "authentication" in lower
158
+ or "api key" in lower
159
+ or "401" in lower
160
+ or "403" in lower
173
161
  ):
174
- logger.error(
175
- f"E2B authentication/authorization error: {e}", exc_info=True
176
- )
177
- raise NotAuthorizedError(
178
- f"E2B authentication failed or access denied: {e}"
179
- )
180
- logger.error(f"Error during E2B code execution: {e}", exc_info=True)
162
+ raise NotAuthorizedError(f"E2B authentication/permission failed: {e}")
181
163
  raise ToolError(f"E2B code execution failed: {e}")
182
164
 
183
165
  def list_tools(self) -> list[callable]:
@@ -153,6 +153,18 @@ class FirecrawlApp(APIApplication):
153
153
 
154
154
  return f"Error during {operation_desc}: {type(e).__name__} - {e}"
155
155
 
156
+ def _to_serializable(self, obj: Any) -> Any:
157
+ """
158
+ Recursively converts Pydantic models to dictionaries for JSON serialization.
159
+ """
160
+ if isinstance(obj, list):
161
+ return [self._to_serializable(item) for item in obj]
162
+ if hasattr(obj, "model_dump"): # Pydantic v2
163
+ return obj.model_dump()
164
+ if hasattr(obj, "dict"): # Pydantic v1
165
+ return obj.dict()
166
+ return obj
167
+
156
168
  def scrape_url(self, url: str) -> Any:
157
169
  """
158
170
  Scrapes a single URL using Firecrawl and returns the extracted data.
@@ -176,7 +188,7 @@ class FirecrawlApp(APIApplication):
176
188
  client = self._get_client()
177
189
  response_data = client.scrape(url=url)
178
190
  logger.info(f"Successfully scraped URL: {url}")
179
- return response_data
191
+ return self._to_serializable(response_data)
180
192
  except NotAuthorizedError:
181
193
  raise
182
194
  except ToolError:
@@ -208,7 +220,7 @@ class FirecrawlApp(APIApplication):
208
220
  client = self._get_client()
209
221
  response = client.search(query=query)
210
222
  logger.info(f"Successfully performed Firecrawl search for query: {query}")
211
- return response # type: ignore
223
+ return self._to_serializable(response)
212
224
  except NotAuthorizedError:
213
225
  raise
214
226
  except ToolError:
@@ -247,13 +259,13 @@ class FirecrawlApp(APIApplication):
247
259
  logger.info(
248
260
  f"Successfully started Firecrawl crawl for URL {url}, Job ID: {job_id}"
249
261
  )
250
- return response # type: ignore
262
+ return self._to_serializable(response)
251
263
  except NotAuthorizedError:
252
264
  raise
253
265
  except ToolError:
254
266
  raise
255
267
  except Exception as e:
256
- return self._handle_firecrawl_exception(e, f"starting crawl for URL {url}") # type: ignore
268
+ return self._handle_firecrawl_exception(e, f"starting crawl for URL {url}")
257
269
 
258
270
  def check_crawl_status(self, job_id: str) -> dict[str, Any] | str:
259
271
  """
@@ -280,7 +292,7 @@ class FirecrawlApp(APIApplication):
280
292
  logger.info(
281
293
  f"Successfully checked Firecrawl crawl status for job ID: {job_id}"
282
294
  )
283
- return status # type: ignore
295
+ return self._to_serializable(status)
284
296
  except NotAuthorizedError:
285
297
  raise
286
298
  except ToolError:
@@ -288,7 +300,7 @@ class FirecrawlApp(APIApplication):
288
300
  except Exception as e:
289
301
  return self._handle_firecrawl_exception(
290
302
  e, f"checking crawl status for job ID {job_id}"
291
- ) # type: ignore
303
+ )
292
304
 
293
305
  def cancel_crawl(self, job_id: str) -> dict[str, Any] | str:
294
306
  """
@@ -316,7 +328,7 @@ class FirecrawlApp(APIApplication):
316
328
  logger.info(
317
329
  f"Successfully issued cancel command for Firecrawl crawl job ID: {job_id}"
318
330
  )
319
- return response # type: ignore
331
+ return self._to_serializable(response)
320
332
  except NotAuthorizedError:
321
333
  raise
322
334
  except ToolError:
@@ -324,7 +336,7 @@ class FirecrawlApp(APIApplication):
324
336
  except Exception as e:
325
337
  return self._handle_firecrawl_exception(
326
338
  e, f"cancelling crawl job ID {job_id}"
327
- ) # type: ignore
339
+ )
328
340
 
329
341
  def start_batch_scrape(
330
342
  self,
@@ -354,7 +366,7 @@ class FirecrawlApp(APIApplication):
354
366
  logger.info(
355
367
  f"Successfully started Firecrawl batch scrape for {len(urls)} URLs."
356
368
  )
357
- return response # type: ignore
369
+ return self._to_serializable(response)
358
370
  except NotAuthorizedError:
359
371
  raise
360
372
  except ToolError:
@@ -362,7 +374,7 @@ class FirecrawlApp(APIApplication):
362
374
  except Exception as e:
363
375
  return self._handle_firecrawl_exception(
364
376
  e, f"starting batch scrape for {len(urls)} URLs"
365
- ) # type: ignore
377
+ )
366
378
 
367
379
  def check_batch_scrape_status(self, job_id: str) -> dict[str, Any] | str:
368
380
  """
@@ -391,7 +403,7 @@ class FirecrawlApp(APIApplication):
391
403
  logger.info(
392
404
  f"Successfully checked Firecrawl batch scrape status for job ID: {job_id}"
393
405
  )
394
- return status # type: ignore
406
+ return self._to_serializable(status)
395
407
  except NotAuthorizedError:
396
408
  raise
397
409
  except ToolError:
@@ -399,7 +411,7 @@ class FirecrawlApp(APIApplication):
399
411
  except Exception as e:
400
412
  return self._handle_firecrawl_exception(
401
413
  e, f"checking batch scrape status for job ID {job_id}"
402
- ) # type: ignore
414
+ )
403
415
 
404
416
  def quick_web_extract(
405
417
  self,
@@ -444,7 +456,7 @@ class FirecrawlApp(APIApplication):
444
456
  logger.info(
445
457
  f"Successfully completed quick web extraction for {len(urls)} URLs."
446
458
  )
447
- return response # type: ignore
459
+ return self._to_serializable(response)
448
460
  except NotAuthorizedError:
449
461
  logger.error("Firecrawl API key missing or invalid.")
450
462
  raise
@@ -490,7 +502,7 @@ class FirecrawlApp(APIApplication):
490
502
  logger.info(
491
503
  f"Successfully checked Firecrawl extraction status for job ID: {job_id}"
492
504
  )
493
- return status # type: ignore
505
+ return self._to_serializable(status)
494
506
  except NotAuthorizedError:
495
507
  raise
496
508
  except ToolError:
@@ -498,7 +510,7 @@ class FirecrawlApp(APIApplication):
498
510
  except Exception as e:
499
511
  return self._handle_firecrawl_exception(
500
512
  e, f"checking extraction status for job ID {job_id}"
501
- ) # type: ignore
513
+ )
502
514
 
503
515
  def list_tools(self):
504
516
  return [
@@ -74,8 +74,10 @@ class GoogleGeminiApp(APIApplication):
74
74
 
75
75
  Args:
76
76
  prompt (str): The prompt to generate image from.
77
+ image (str, optional): The reference image path url.
77
78
  model (str, optional): The Gemini model to use for image generation. Defaults to "gemini-2.5-flash-image-preview".
78
79
 
80
+
79
81
  Returns:
80
82
  list: A list of dicts, each containing either 'text' or 'image_bytes'.
81
83
 
@@ -85,7 +87,13 @@ class GoogleGeminiApp(APIApplication):
85
87
  # The Gemini API is synchronous, so run in a thread
86
88
  contents = [prompt]
87
89
  if image:
88
- image = Image.open(image)
90
+ if image.startswith(('http://', 'https://')):
91
+ import requests
92
+ response = requests.get(image)
93
+ response.raise_for_status()
94
+ image = Image.open(io.BytesIO(response.content))
95
+ else:
96
+ image = Image.open(image)
89
97
  contents.append(image)
90
98
  response = self.genai_client.models.generate_content(
91
99
  model=model,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp-applications
3
- Version: 0.1.8
3
+ Version: 0.1.9
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
@@ -57,7 +57,7 @@ universal_mcp/applications/domain_checker/__init__.py,sha256=4s7K0D6jORpJAUySJS1
57
57
  universal_mcp/applications/domain_checker/app.py,sha256=R-uXWkG0pMrdyAGgsIxBGLfxbChB05d02xN5mj5NEPI,9915
58
58
  universal_mcp/applications/e2b/README.md,sha256=King2LmyUlseNZ76c3bmsJCxg8PHhCQMzVcN35l_-qc,296
59
59
  universal_mcp/applications/e2b/__init__.py,sha256=hL17jBumsx-oi93AAIFCoDdoP7zQElnrTjnCDc7NBH4,24
60
- universal_mcp/applications/e2b/app.py,sha256=Vosateq-bIuez7h2M7P01do3ZAU3_WNKSKUommHrirc,7560
60
+ universal_mcp/applications/e2b/app.py,sha256=qWpOtGf1YkQXWVu6igKrWj03wcrtS8zAMtaQOtTM56I,6834
61
61
  universal_mcp/applications/elevenlabs/README.md,sha256=xftSdiuQjBLyx9uYK7re4uUp2Pwrni5678-O2Tzqu2I,10940
62
62
  universal_mcp/applications/elevenlabs/__init__.py,sha256=2ojwxRFjYEwBieAqUZlPJulRfOaoPrCrqeEiZNxG48M,31
63
63
  universal_mcp/applications/elevenlabs/app.py,sha256=bQQOi6KhqtYygcQLFv7abOeV54kpkmABUgZhIjPC72U,4886
@@ -74,7 +74,7 @@ universal_mcp/applications/file_system/__init__.py,sha256=ZW4Iac5_Gho-FYaxIsnCs1
74
74
  universal_mcp/applications/file_system/app.py,sha256=YbMSDPpvetmVQP0aTJSVqQaX-ZgNP121Ikb9BjnSBhs,3102
75
75
  universal_mcp/applications/firecrawl/README.md,sha256=BeUZ2IPckHC_JuxW6daai5qxfw2SbLjIsfh6PNcDbBU,1189
76
76
  universal_mcp/applications/firecrawl/__init__.py,sha256=Sl2LuCKsNHoFf-3dGE31CYVGJkF_lJBvx34XVtZPr5I,30
77
- universal_mcp/applications/firecrawl/app.py,sha256=glh7tcQKSL0DswTGEPnS1RG6sWQkdadrjc2SGTXTU6I,19264
77
+ universal_mcp/applications/firecrawl/app.py,sha256=dNUZbXBo3jDSA-PhDKqlVr6Aa6m3tOE6v_qn3Vlp7rU,19692
78
78
  universal_mcp/applications/fireflies/README.md,sha256=l5iDCzF-diIh9gHptB8g4UzzWNLqUCq9rR164bhU7A4,1203
79
79
  universal_mcp/applications/fireflies/__init__.py,sha256=SMEk3MeSk6aFzX8GX_NZwcjBvnEeTRQDlA1RZMrwKxA,30
80
80
  universal_mcp/applications/fireflies/app.py,sha256=XQrlxlZGhc9dIMb9J1ECbdDvJ7ktGmFHJ5fVJ45-k1A,15646
@@ -106,7 +106,7 @@ universal_mcp/applications/google_drive/__init__.py,sha256=DTyed4ADcCmALSyPT8whj
106
106
  universal_mcp/applications/google_drive/app.py,sha256=IlYwUxGRo7ISKGeWzWpc_0r4ewDo-rXLPChyMOxAc_Q,248993
107
107
  universal_mcp/applications/google_gemini/README.md,sha256=o5cWenioUnNhn7L2fxwPLasBXzQ7mNmYp-aLLj9bHzY,2042
108
108
  universal_mcp/applications/google_gemini/__init__.py,sha256=KZWdPU74VKBBabLpAcPNEPRPLFk8v2i0ULnT4wVHM9U,33
109
- universal_mcp/applications/google_gemini/app.py,sha256=2IZ_TqW5wRhAeqFchlpejfwE1azWmS_WuUqkxDt77vw,6214
109
+ universal_mcp/applications/google_gemini/app.py,sha256=9wLuCvpdIwB5kHH2tLBgPiVkZcqgYK5mitVCPqAgWxA,6548
110
110
  universal_mcp/applications/google_mail/README.md,sha256=TVLbil9-qjjp9kZziuWWhkiVNR1tf5XJ_q37xd6iUsg,2422
111
111
  universal_mcp/applications/google_mail/__init__.py,sha256=_VpJPPBAJvPX3urxUD2_kiQmld91tkVFSvAcdt5XbmI,31
112
112
  universal_mcp/applications/google_mail/app.py,sha256=vT3Lg2qZNX98PPjJ-nDkA4VtZvofu_nkXuqRo4w2Xpo,54892
@@ -267,7 +267,7 @@ universal_mcp/applications/youtube/app.py,sha256=hhKqnbXvMAyOW3LOqp-ODPdIuQorr1n
267
267
  universal_mcp/applications/zenquotes/README.md,sha256=x1mZHjNKD4WOgsIhedcbbaR1nvbt794GSrKud1tSLD0,296
268
268
  universal_mcp/applications/zenquotes/__init__.py,sha256=IkASLYaZiHJXlkGwEMk1HgIq5GwEZp5GhAIiJyjBd3g,30
269
269
  universal_mcp/applications/zenquotes/app.py,sha256=6v8trNWjxbixdlEyaM-gJbfY8z9ZAmkIzSUks_fbsT4,1076
270
- universal_mcp_applications-0.1.8.dist-info/METADATA,sha256=YGInMpijLj_8Wp9K_we7dd6Kpf1cP7FeyA3NTrdl3uU,3918
271
- universal_mcp_applications-0.1.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
272
- universal_mcp_applications-0.1.8.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
273
- universal_mcp_applications-0.1.8.dist-info/RECORD,,
270
+ universal_mcp_applications-0.1.9.dist-info/METADATA,sha256=WDVudmb54yXf4ekHrSDEiWO2R8fGeGf-IqN6clCcjdk,3918
271
+ universal_mcp_applications-0.1.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
272
+ universal_mcp_applications-0.1.9.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
273
+ universal_mcp_applications-0.1.9.dist-info/RECORD,,