universal-mcp-applications 0.1.33__py3-none-any.whl → 0.1.39rc8__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.

Files changed (113) hide show
  1. universal_mcp/applications/ahrefs/app.py +92 -238
  2. universal_mcp/applications/airtable/app.py +23 -122
  3. universal_mcp/applications/apollo/app.py +122 -475
  4. universal_mcp/applications/asana/app.py +605 -1755
  5. universal_mcp/applications/aws_s3/app.py +36 -103
  6. universal_mcp/applications/bill/app.py +644 -2055
  7. universal_mcp/applications/box/app.py +1246 -4159
  8. universal_mcp/applications/braze/app.py +410 -1476
  9. universal_mcp/applications/browser_use/README.md +15 -1
  10. universal_mcp/applications/browser_use/__init__.py +1 -0
  11. universal_mcp/applications/browser_use/app.py +86 -24
  12. universal_mcp/applications/cal_com_v2/app.py +207 -625
  13. universal_mcp/applications/calendly/app.py +103 -242
  14. universal_mcp/applications/canva/app.py +75 -140
  15. universal_mcp/applications/clickup/app.py +331 -798
  16. universal_mcp/applications/coda/app.py +240 -520
  17. universal_mcp/applications/confluence/app.py +497 -1285
  18. universal_mcp/applications/contentful/app.py +36 -151
  19. universal_mcp/applications/crustdata/app.py +42 -121
  20. universal_mcp/applications/dialpad/app.py +451 -924
  21. universal_mcp/applications/digitalocean/app.py +2071 -6082
  22. universal_mcp/applications/domain_checker/app.py +3 -54
  23. universal_mcp/applications/e2b/app.py +14 -64
  24. universal_mcp/applications/elevenlabs/app.py +9 -47
  25. universal_mcp/applications/exa/README.md +8 -4
  26. universal_mcp/applications/exa/app.py +408 -186
  27. universal_mcp/applications/falai/app.py +24 -101
  28. universal_mcp/applications/figma/app.py +91 -175
  29. universal_mcp/applications/file_system/app.py +2 -13
  30. universal_mcp/applications/firecrawl/app.py +186 -163
  31. universal_mcp/applications/fireflies/app.py +59 -281
  32. universal_mcp/applications/fpl/app.py +92 -529
  33. universal_mcp/applications/fpl/utils/fixtures.py +15 -49
  34. universal_mcp/applications/fpl/utils/helper.py +25 -89
  35. universal_mcp/applications/fpl/utils/league_utils.py +20 -64
  36. universal_mcp/applications/ghost_content/app.py +66 -175
  37. universal_mcp/applications/github/app.py +28 -65
  38. universal_mcp/applications/gong/app.py +140 -300
  39. universal_mcp/applications/google_calendar/app.py +26 -78
  40. universal_mcp/applications/google_docs/app.py +98 -202
  41. universal_mcp/applications/google_drive/app.py +194 -793
  42. universal_mcp/applications/google_gemini/app.py +27 -62
  43. universal_mcp/applications/google_mail/README.md +1 -0
  44. universal_mcp/applications/google_mail/app.py +93 -214
  45. universal_mcp/applications/google_searchconsole/app.py +25 -58
  46. universal_mcp/applications/google_sheet/app.py +171 -624
  47. universal_mcp/applications/google_sheet/helper.py +26 -53
  48. universal_mcp/applications/hashnode/app.py +57 -269
  49. universal_mcp/applications/heygen/app.py +77 -155
  50. universal_mcp/applications/http_tools/app.py +10 -32
  51. universal_mcp/applications/hubspot/README.md +1 -1
  52. universal_mcp/applications/hubspot/app.py +7508 -99
  53. universal_mcp/applications/jira/app.py +2419 -8334
  54. universal_mcp/applications/klaviyo/app.py +737 -1619
  55. universal_mcp/applications/linkedin/README.md +5 -0
  56. universal_mcp/applications/linkedin/app.py +332 -227
  57. universal_mcp/applications/mailchimp/app.py +696 -1851
  58. universal_mcp/applications/markitdown/app.py +8 -20
  59. universal_mcp/applications/miro/app.py +333 -815
  60. universal_mcp/applications/ms_teams/app.py +85 -207
  61. universal_mcp/applications/neon/app.py +144 -250
  62. universal_mcp/applications/notion/app.py +36 -51
  63. universal_mcp/applications/onedrive/app.py +26 -48
  64. universal_mcp/applications/openai/app.py +42 -165
  65. universal_mcp/applications/outlook/README.md +22 -9
  66. universal_mcp/applications/outlook/app.py +403 -141
  67. universal_mcp/applications/perplexity/README.md +2 -1
  68. universal_mcp/applications/perplexity/app.py +162 -20
  69. universal_mcp/applications/pipedrive/app.py +1021 -3331
  70. universal_mcp/applications/posthog/app.py +272 -541
  71. universal_mcp/applications/reddit/app.py +61 -160
  72. universal_mcp/applications/resend/app.py +41 -107
  73. universal_mcp/applications/retell/app.py +23 -50
  74. universal_mcp/applications/rocketlane/app.py +250 -963
  75. universal_mcp/applications/scraper/app.py +67 -125
  76. universal_mcp/applications/semanticscholar/app.py +36 -78
  77. universal_mcp/applications/semrush/app.py +43 -77
  78. universal_mcp/applications/sendgrid/app.py +826 -1576
  79. universal_mcp/applications/sentry/app.py +444 -1079
  80. universal_mcp/applications/serpapi/app.py +40 -143
  81. universal_mcp/applications/sharepoint/app.py +27 -49
  82. universal_mcp/applications/shopify/app.py +1743 -4479
  83. universal_mcp/applications/shortcut/app.py +272 -534
  84. universal_mcp/applications/slack/app.py +41 -123
  85. universal_mcp/applications/spotify/app.py +206 -405
  86. universal_mcp/applications/supabase/app.py +174 -283
  87. universal_mcp/applications/tavily/app.py +2 -2
  88. universal_mcp/applications/trello/app.py +853 -2816
  89. universal_mcp/applications/twilio/app.py +14 -50
  90. universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
  91. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
  92. universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
  93. universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
  94. universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
  95. universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
  96. universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
  97. universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
  98. universal_mcp/applications/whatsapp/app.py +35 -186
  99. universal_mcp/applications/whatsapp/audio.py +2 -6
  100. universal_mcp/applications/whatsapp/whatsapp.py +17 -51
  101. universal_mcp/applications/whatsapp_business/app.py +86 -299
  102. universal_mcp/applications/wrike/app.py +80 -153
  103. universal_mcp/applications/yahoo_finance/app.py +19 -65
  104. universal_mcp/applications/youtube/app.py +120 -306
  105. universal_mcp/applications/zenquotes/app.py +3 -3
  106. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/METADATA +4 -2
  107. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/RECORD +109 -113
  108. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/WHEEL +1 -1
  109. universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
  110. universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
  111. universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
  112. universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
  113. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/licenses/LICENSE +0 -0
@@ -9,4 +9,5 @@ This is automatically generated from OpenAPI schema for the PerplexityApp API.
9
9
 
10
10
  | Tool | Description |
11
11
  |------|-------------|
12
- | `answer_with_search` | Queries the Perplexity Chat Completions API for a web-search-grounded answer. It sends the user's prompt and model parameters to the `/chat/completions` endpoint, then parses the response to return the synthesized content and a list of supporting source citations, ideal for real-time information retrieval. |
12
+ | `answer_with_search` | Queries the Perplexity Chat Completions API for a web-search-grounded answer. It sends the user's prompt and model parameters to the `/chat/completions` endpoint, then parses the response to return the synthesized content and a list of supporting source citations. |
13
+ | `search` | Performs a real-time web search using Perplexity AI to answer a query with up-to-date information and citations. |
@@ -1,15 +1,75 @@
1
1
  from typing import Any, Literal
2
-
2
+ from loguru import logger
3
3
  from universal_mcp.applications.application import APIApplication
4
+ from universal_mcp.exceptions import NotAuthorizedError, ToolError
4
5
  from universal_mcp.integrations import Integration
5
6
 
7
+ try:
8
+ from perplexity import AsyncPerplexity
9
+ except ImportError:
10
+ AsyncPerplexity = None # type: ignore
11
+ logger.error("Failed to import perplexity. Please ensure 'perplexityai' is installed.")
12
+
6
13
 
7
14
  class PerplexityApp(APIApplication):
8
15
  def __init__(self, integration: Integration | None = None) -> None:
9
16
  super().__init__(name="perplexity", integration=integration)
10
- self.base_url = "https://api.perplexity.ai"
17
+ self._perplexity_api_key: str | None = None
18
+ if AsyncPerplexity is None:
19
+ logger.warning("Perplexity SDK is not available. Perplexity tools will not function.")
20
+
21
+ @property
22
+ def perplexity_api_key(self) -> str:
23
+ """
24
+ A property that lazily retrieves and caches the Perplexity API key from the configured integration.
25
+ """
26
+ if self._perplexity_api_key is None:
27
+ if not self.integration:
28
+ logger.error(f"{self.name.capitalize()} App: Integration not configured.")
29
+ raise NotAuthorizedError(f"Integration not configured for {self.name.capitalize()} App. Cannot retrieve API key.")
30
+ try:
31
+ credentials = self.integration.get_credentials()
32
+ except NotAuthorizedError as e:
33
+ logger.error(f"{self.name.capitalize()} App: Authorization error when fetching credentials: {e.message}")
34
+ raise
35
+ except Exception as e:
36
+ logger.error(f"{self.name.capitalize()} App: Unexpected error when fetching credentials: {e}", exc_info=True)
37
+ raise NotAuthorizedError(f"Failed to get {self.name.capitalize()} credentials: {e}")
38
+
39
+ # Check for common key names
40
+ api_key = credentials.get("api_key") or credentials.get("API_KEY") or credentials.get("apiKey") or credentials.get("PPLX_API_KEY")
41
+
42
+ if not api_key:
43
+ logger.error(f"{self.name.capitalize()} App: API key not found in credentials.")
44
+ action_message = f"API key for {self.name.capitalize()} is missing. Please ensure it's set in the store."
45
+ if hasattr(self.integration, "authorize") and callable(self.integration.authorize):
46
+ try:
47
+ auth_details = self.integration.authorize()
48
+ if isinstance(auth_details, str):
49
+ action_message = auth_details
50
+ elif isinstance(auth_details, dict) and "url" in auth_details:
51
+ action_message = f"Please authorize via: {auth_details['url']}"
52
+ elif isinstance(auth_details, dict) and "message" in auth_details:
53
+ action_message = auth_details["message"]
54
+ except Exception as auth_e:
55
+ logger.warning(f"Could not retrieve specific authorization action for {self.name.capitalize()}: {auth_e}")
56
+ raise NotAuthorizedError(action_message)
57
+ self._perplexity_api_key = api_key
58
+ logger.info(f"{self.name.capitalize()} API Key successfully retrieved and cached.")
59
+ assert self._perplexity_api_key is not None
60
+ return self._perplexity_api_key
61
+
62
+ def _get_client(self) -> AsyncPerplexity:
63
+ """
64
+ Initializes and returns the Perplexity client after ensuring API key is set.
65
+ """
66
+ if AsyncPerplexity is None:
67
+ logger.error("Perplexity SDK is not available.")
68
+ raise ToolError("Perplexity SDK is not installed or failed to import.")
69
+ current_api_key = self.perplexity_api_key
70
+ return AsyncPerplexity(api_key=current_api_key)
11
71
 
12
- def answer_with_search(
72
+ async def answer_with_search(
13
73
  self,
14
74
  query: str,
15
75
  model: Literal[
@@ -22,44 +82,126 @@ class PerplexityApp(APIApplication):
22
82
  ] = "sonar-pro",
23
83
  temperature: float = 1,
24
84
  system_prompt: str = "You are a helpful AI assistant that answers questions using real-time information from the web.",
85
+ response_format: dict[str, Any] | None = None,
86
+ json_schema: dict[str, Any] | None = None,
87
+ regex: str | None = None,
25
88
  ) -> dict[str, Any] | str:
26
89
  """
27
- Queries the Perplexity Chat Completions API for a web-search-grounded answer. It sends the user's prompt and model parameters to the `/chat/completions` endpoint, then parses the response to return the synthesized content and a list of supporting source citations, ideal for real-time information retrieval.
90
+ Queries the Perplexity Chat Completions API for a web-search-grounded answer. It sends the user's prompt and model parameters to the `/chat/completions` endpoint, then parses the response to return the synthesized content and a list of supporting source citations.
91
+
92
+ This method supports **Structured Outputs** using `json_schema` or `regex` to enforce specific response formats.
28
93
 
29
94
  Args:
30
- query: The search query or question to ask. For example: "What are the latest developments in AI regulation?"
95
+ query: The search query or question to ask.
31
96
  model: The Perplexity model to use.
32
- temperature: Controls randomness in the model's output. Higher values make the output more random, lower values make it more deterministic. Defaults to 1.
97
+ temperature: Controls randomness in the model's output.
33
98
  system_prompt: The initial system message to guide the model's behavior.
99
+ response_format: A dict specifying the response format (e.g. `{"type": "json_schema", ...}`).
100
+ json_schema: A dictionary for the JSON schema to enforce (shortcut for `response_format`).
101
+ regex: A regex string to enforce (shortcut for `response_format`, only available for 'sonar').
34
102
 
35
103
  Returns:
36
104
  A dictionary containing the generated 'content' (str) and a list of 'citations' (list) from the web search.
37
105
 
106
+ Examples:
107
+ **1. Financial Analysis with JSON Schema**
108
+ ```python
109
+ from pydantic import BaseModel
110
+ class FinancialMetrics(BaseModel):
111
+ company: str
112
+ revenue: float
113
+ net_income: float
114
+
115
+ app.answer_with_search(
116
+ "Analyze Apple's latest earnings",
117
+ model="sonar-pro",
118
+ json_schema={"schema": FinancialMetrics.model_json_schema()}
119
+ )
120
+ ```
121
+
122
+ **2. Extract Contact Information with Regex**
123
+ ```python
124
+ app.answer_with_search(
125
+ "Find the investor relations email for Tesla",
126
+ model="sonar",
127
+ regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
128
+ )
129
+ ```
130
+
38
131
  Raises:
39
- AuthenticationError: Raised when API authentication fails due to missing or invalid credentials.
40
- HTTPError: Raised when the API request fails or returns an error status.
132
+ AuthenticationError: Raised when API authentication fails.
133
+ HTTPError: Raised when the API request fails.
134
+ ValueError: If conflicting structured output parameters are provided.
41
135
 
42
136
  Tags:
43
- search, web, research, citations, current events, important
137
+ chat, answer, search, web, research, citations, structured_output, extraction, important
44
138
  """
45
- endpoint = f"{self.base_url}/chat/completions"
139
+ if sum(x is not None for x in [response_format, json_schema, regex]) > 1:
140
+ raise ValueError("Only one of 'response_format', 'json_schema', or 'regex' can be provided.")
141
+
142
+ if json_schema:
143
+ response_format = {"type": "json_schema", "json_schema": json_schema}
144
+ elif regex:
145
+ response_format = {"type": "regex", "regex": {"regex": regex}}
146
+
46
147
  messages = []
47
148
  if system_prompt:
48
149
  messages.append({"role": "system", "content": system_prompt})
49
150
  messages.append({"role": "user", "content": query})
50
- payload = {
151
+
152
+ client = self._get_client()
153
+ # client.chat.completions.create supports response_format
154
+ kwargs: dict[str, Any] = {
51
155
  "model": model,
52
- "messages": messages,
156
+ "messages": messages, # type: ignore
53
157
  "temperature": temperature,
54
- # "max_tokens": 512,
55
158
  }
56
- data = self._post(endpoint, data=payload)
57
- response = data.json()
58
- content = response["choices"][0]["message"]["content"]
59
- citations = response.get("citations", [])
159
+ if response_format:
160
+ kwargs["response_format"] = response_format
161
+
162
+ response = await client.chat.completions.create(**kwargs)
163
+
164
+ # Assuming response structure matches OpenAI-like usage or Custom as per SDK docs
165
+ content = response.choices[0].message.content
166
+ citations = getattr(response, "citations", [])
60
167
  return {"content": content, "citations": citations}
61
168
 
169
+ async def search(
170
+ self,
171
+ query: str,
172
+ max_results: int = 5,
173
+ country: str = "US",
174
+ ) -> list[dict[str, Any]]:
175
+ """
176
+ Performs a real-time web search using Perplexity AI to answer a query with up-to-date information and citations.
177
+ This tool is ideal for questions about current events, facts, or any topic that requires access to the latest information from the internet.
178
+
179
+ Args:
180
+ query: The search query or question to ask.
181
+ max_results: Maximum number of results to return.
182
+ country: ISO 3166-1 alpha-2 country code for localized results.
183
+
184
+ Returns:
185
+ A list of search results.
186
+
187
+ Tags:
188
+ search, web, research, citations, current events, important
189
+ """
190
+ client = self._get_client()
191
+ response = await client.search.create(
192
+ query=query,
193
+ max_results=max_results,
194
+ country=country,
195
+ )
196
+ results = []
197
+ for result in response.results:
198
+ results.append({
199
+ "title": result.title,
200
+ "url": result.url,
201
+ "snippet": result.snippet,
202
+ "date": result.date,
203
+ })
204
+ return results
205
+
62
206
  def list_tools(self):
63
- return [
64
- self.answer_with_search,
65
- ]
207
+ return [self.answer_with_search, self.search]