universal-mcp-applications 0.1.1__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.
Files changed (268) hide show
  1. universal_mcp/applications/ahrefs/README.md +51 -0
  2. universal_mcp/applications/ahrefs/__init__.py +1 -0
  3. universal_mcp/applications/ahrefs/app.py +2291 -0
  4. universal_mcp/applications/airtable/README.md +22 -0
  5. universal_mcp/applications/airtable/__init__.py +1 -0
  6. universal_mcp/applications/airtable/app.py +479 -0
  7. universal_mcp/applications/apollo/README.md +44 -0
  8. universal_mcp/applications/apollo/__init__.py +1 -0
  9. universal_mcp/applications/apollo/app.py +1847 -0
  10. universal_mcp/applications/asana/README.md +199 -0
  11. universal_mcp/applications/asana/__init__.py +1 -0
  12. universal_mcp/applications/asana/app.py +9509 -0
  13. universal_mcp/applications/aws-s3/README.md +0 -0
  14. universal_mcp/applications/aws-s3/__init__.py +1 -0
  15. universal_mcp/applications/aws-s3/app.py +552 -0
  16. universal_mcp/applications/bill/README.md +0 -0
  17. universal_mcp/applications/bill/__init__.py +1 -0
  18. universal_mcp/applications/bill/app.py +8705 -0
  19. universal_mcp/applications/box/README.md +307 -0
  20. universal_mcp/applications/box/__init__.py +1 -0
  21. universal_mcp/applications/box/app.py +15987 -0
  22. universal_mcp/applications/braze/README.md +106 -0
  23. universal_mcp/applications/braze/__init__.py +1 -0
  24. universal_mcp/applications/braze/app.py +4754 -0
  25. universal_mcp/applications/cal-com-v2/README.md +150 -0
  26. universal_mcp/applications/cal-com-v2/__init__.py +1 -0
  27. universal_mcp/applications/cal-com-v2/app.py +5541 -0
  28. universal_mcp/applications/calendly/README.md +53 -0
  29. universal_mcp/applications/calendly/__init__.py +1 -0
  30. universal_mcp/applications/calendly/app.py +1436 -0
  31. universal_mcp/applications/canva/README.md +43 -0
  32. universal_mcp/applications/canva/__init__.py +1 -0
  33. universal_mcp/applications/canva/app.py +941 -0
  34. universal_mcp/applications/clickup/README.md +135 -0
  35. universal_mcp/applications/clickup/__init__.py +1 -0
  36. universal_mcp/applications/clickup/app.py +5009 -0
  37. universal_mcp/applications/coda/README.md +108 -0
  38. universal_mcp/applications/coda/__init__.py +1 -0
  39. universal_mcp/applications/coda/app.py +3671 -0
  40. universal_mcp/applications/confluence/README.md +198 -0
  41. universal_mcp/applications/confluence/__init__.py +1 -0
  42. universal_mcp/applications/confluence/app.py +6273 -0
  43. universal_mcp/applications/contentful/README.md +17 -0
  44. universal_mcp/applications/contentful/__init__.py +1 -0
  45. universal_mcp/applications/contentful/app.py +364 -0
  46. universal_mcp/applications/crustdata/README.md +25 -0
  47. universal_mcp/applications/crustdata/__init__.py +1 -0
  48. universal_mcp/applications/crustdata/app.py +586 -0
  49. universal_mcp/applications/dialpad/README.md +202 -0
  50. universal_mcp/applications/dialpad/__init__.py +1 -0
  51. universal_mcp/applications/dialpad/app.py +5949 -0
  52. universal_mcp/applications/digitalocean/README.md +463 -0
  53. universal_mcp/applications/digitalocean/__init__.py +1 -0
  54. universal_mcp/applications/digitalocean/app.py +20835 -0
  55. universal_mcp/applications/domain-checker/README.md +13 -0
  56. universal_mcp/applications/domain-checker/__init__.py +1 -0
  57. universal_mcp/applications/domain-checker/app.py +265 -0
  58. universal_mcp/applications/e2b/README.md +12 -0
  59. universal_mcp/applications/e2b/__init__.py +1 -0
  60. universal_mcp/applications/e2b/app.py +187 -0
  61. universal_mcp/applications/elevenlabs/README.md +88 -0
  62. universal_mcp/applications/elevenlabs/__init__.py +1 -0
  63. universal_mcp/applications/elevenlabs/app.py +3235 -0
  64. universal_mcp/applications/exa/README.md +15 -0
  65. universal_mcp/applications/exa/__init__.py +1 -0
  66. universal_mcp/applications/exa/app.py +221 -0
  67. universal_mcp/applications/falai/README.md +17 -0
  68. universal_mcp/applications/falai/__init__.py +1 -0
  69. universal_mcp/applications/falai/app.py +331 -0
  70. universal_mcp/applications/figma/README.md +49 -0
  71. universal_mcp/applications/figma/__init__.py +1 -0
  72. universal_mcp/applications/figma/app.py +1090 -0
  73. universal_mcp/applications/firecrawl/README.md +20 -0
  74. universal_mcp/applications/firecrawl/__init__.py +1 -0
  75. universal_mcp/applications/firecrawl/app.py +514 -0
  76. universal_mcp/applications/fireflies/README.md +25 -0
  77. universal_mcp/applications/fireflies/__init__.py +1 -0
  78. universal_mcp/applications/fireflies/app.py +506 -0
  79. universal_mcp/applications/fpl/README.md +23 -0
  80. universal_mcp/applications/fpl/__init__.py +1 -0
  81. universal_mcp/applications/fpl/app.py +1327 -0
  82. universal_mcp/applications/fpl/utils/api.py +142 -0
  83. universal_mcp/applications/fpl/utils/fixtures.py +629 -0
  84. universal_mcp/applications/fpl/utils/helper.py +982 -0
  85. universal_mcp/applications/fpl/utils/league_utils.py +546 -0
  86. universal_mcp/applications/fpl/utils/position_utils.py +68 -0
  87. universal_mcp/applications/ghost-content/README.md +25 -0
  88. universal_mcp/applications/ghost-content/__init__.py +1 -0
  89. universal_mcp/applications/ghost-content/app.py +654 -0
  90. universal_mcp/applications/github/README.md +1049 -0
  91. universal_mcp/applications/github/__init__.py +1 -0
  92. universal_mcp/applications/github/app.py +50600 -0
  93. universal_mcp/applications/gong/README.md +63 -0
  94. universal_mcp/applications/gong/__init__.py +1 -0
  95. universal_mcp/applications/gong/app.py +2297 -0
  96. universal_mcp/applications/google-ads/README.md +0 -0
  97. universal_mcp/applications/google-ads/__init__.py +1 -0
  98. universal_mcp/applications/google-ads/app.py +23 -0
  99. universal_mcp/applications/google-calendar/README.md +21 -0
  100. universal_mcp/applications/google-calendar/__init__.py +1 -0
  101. universal_mcp/applications/google-calendar/app.py +574 -0
  102. universal_mcp/applications/google-docs/README.md +25 -0
  103. universal_mcp/applications/google-docs/__init__.py +1 -0
  104. universal_mcp/applications/google-docs/app.py +760 -0
  105. universal_mcp/applications/google-drive/README.md +68 -0
  106. universal_mcp/applications/google-drive/__init__.py +1 -0
  107. universal_mcp/applications/google-drive/app.py +4936 -0
  108. universal_mcp/applications/google-gemini/README.md +25 -0
  109. universal_mcp/applications/google-gemini/__init__.py +1 -0
  110. universal_mcp/applications/google-gemini/app.py +663 -0
  111. universal_mcp/applications/google-mail/README.md +31 -0
  112. universal_mcp/applications/google-mail/__init__.py +1 -0
  113. universal_mcp/applications/google-mail/app.py +1354 -0
  114. universal_mcp/applications/google-searchconsole/README.md +21 -0
  115. universal_mcp/applications/google-searchconsole/__init__.py +1 -0
  116. universal_mcp/applications/google-searchconsole/app.py +320 -0
  117. universal_mcp/applications/google-sheet/README.md +36 -0
  118. universal_mcp/applications/google-sheet/__init__.py +1 -0
  119. universal_mcp/applications/google-sheet/app.py +1941 -0
  120. universal_mcp/applications/hashnode/README.md +20 -0
  121. universal_mcp/applications/hashnode/__init__.py +1 -0
  122. universal_mcp/applications/hashnode/app.py +455 -0
  123. universal_mcp/applications/heygen/README.md +44 -0
  124. universal_mcp/applications/heygen/__init__.py +1 -0
  125. universal_mcp/applications/heygen/app.py +961 -0
  126. universal_mcp/applications/http-tools/README.md +16 -0
  127. universal_mcp/applications/http-tools/__init__.py +1 -0
  128. universal_mcp/applications/http-tools/app.py +153 -0
  129. universal_mcp/applications/hubspot/README.md +239 -0
  130. universal_mcp/applications/hubspot/__init__.py +1 -0
  131. universal_mcp/applications/hubspot/app.py +416 -0
  132. universal_mcp/applications/jira/README.md +600 -0
  133. universal_mcp/applications/jira/__init__.py +1 -0
  134. universal_mcp/applications/jira/app.py +28804 -0
  135. universal_mcp/applications/klaviyo/README.md +313 -0
  136. universal_mcp/applications/klaviyo/__init__.py +1 -0
  137. universal_mcp/applications/klaviyo/app.py +11236 -0
  138. universal_mcp/applications/linkedin/README.md +15 -0
  139. universal_mcp/applications/linkedin/__init__.py +1 -0
  140. universal_mcp/applications/linkedin/app.py +243 -0
  141. universal_mcp/applications/mailchimp/README.md +281 -0
  142. universal_mcp/applications/mailchimp/__init__.py +1 -0
  143. universal_mcp/applications/mailchimp/app.py +10937 -0
  144. universal_mcp/applications/markitdown/README.md +12 -0
  145. universal_mcp/applications/markitdown/__init__.py +1 -0
  146. universal_mcp/applications/markitdown/app.py +63 -0
  147. universal_mcp/applications/miro/README.md +151 -0
  148. universal_mcp/applications/miro/__init__.py +1 -0
  149. universal_mcp/applications/miro/app.py +5429 -0
  150. universal_mcp/applications/ms-teams/README.md +42 -0
  151. universal_mcp/applications/ms-teams/__init__.py +1 -0
  152. universal_mcp/applications/ms-teams/app.py +1823 -0
  153. universal_mcp/applications/neon/README.md +74 -0
  154. universal_mcp/applications/neon/__init__.py +1 -0
  155. universal_mcp/applications/neon/app.py +2018 -0
  156. universal_mcp/applications/notion/README.md +30 -0
  157. universal_mcp/applications/notion/__init__.py +1 -0
  158. universal_mcp/applications/notion/app.py +527 -0
  159. universal_mcp/applications/openai/README.md +22 -0
  160. universal_mcp/applications/openai/__init__.py +1 -0
  161. universal_mcp/applications/openai/app.py +759 -0
  162. universal_mcp/applications/outlook/README.md +20 -0
  163. universal_mcp/applications/outlook/__init__.py +1 -0
  164. universal_mcp/applications/outlook/app.py +444 -0
  165. universal_mcp/applications/perplexity/README.md +12 -0
  166. universal_mcp/applications/perplexity/__init__.py +1 -0
  167. universal_mcp/applications/perplexity/app.py +65 -0
  168. universal_mcp/applications/pipedrive/README.md +284 -0
  169. universal_mcp/applications/pipedrive/__init__.py +1 -0
  170. universal_mcp/applications/pipedrive/app.py +12924 -0
  171. universal_mcp/applications/posthog/README.md +132 -0
  172. universal_mcp/applications/posthog/__init__.py +1 -0
  173. universal_mcp/applications/posthog/app.py +7125 -0
  174. universal_mcp/applications/reddit/README.md +135 -0
  175. universal_mcp/applications/reddit/__init__.py +1 -0
  176. universal_mcp/applications/reddit/app.py +4652 -0
  177. universal_mcp/applications/replicate/README.md +18 -0
  178. universal_mcp/applications/replicate/__init__.py +1 -0
  179. universal_mcp/applications/replicate/app.py +495 -0
  180. universal_mcp/applications/resend/README.md +40 -0
  181. universal_mcp/applications/resend/__init__.py +1 -0
  182. universal_mcp/applications/resend/app.py +881 -0
  183. universal_mcp/applications/retell/README.md +21 -0
  184. universal_mcp/applications/retell/__init__.py +1 -0
  185. universal_mcp/applications/retell/app.py +333 -0
  186. universal_mcp/applications/rocketlane/README.md +70 -0
  187. universal_mcp/applications/rocketlane/__init__.py +1 -0
  188. universal_mcp/applications/rocketlane/app.py +4346 -0
  189. universal_mcp/applications/semanticscholar/README.md +25 -0
  190. universal_mcp/applications/semanticscholar/__init__.py +1 -0
  191. universal_mcp/applications/semanticscholar/app.py +482 -0
  192. universal_mcp/applications/semrush/README.md +44 -0
  193. universal_mcp/applications/semrush/__init__.py +1 -0
  194. universal_mcp/applications/semrush/app.py +2081 -0
  195. universal_mcp/applications/sendgrid/README.md +362 -0
  196. universal_mcp/applications/sendgrid/__init__.py +1 -0
  197. universal_mcp/applications/sendgrid/app.py +9752 -0
  198. universal_mcp/applications/sentry/README.md +186 -0
  199. universal_mcp/applications/sentry/__init__.py +1 -0
  200. universal_mcp/applications/sentry/app.py +7471 -0
  201. universal_mcp/applications/serpapi/README.md +14 -0
  202. universal_mcp/applications/serpapi/__init__.py +1 -0
  203. universal_mcp/applications/serpapi/app.py +293 -0
  204. universal_mcp/applications/sharepoint/README.md +0 -0
  205. universal_mcp/applications/sharepoint/__init__.py +1 -0
  206. universal_mcp/applications/sharepoint/app.py +215 -0
  207. universal_mcp/applications/shopify/README.md +321 -0
  208. universal_mcp/applications/shopify/__init__.py +1 -0
  209. universal_mcp/applications/shopify/app.py +15392 -0
  210. universal_mcp/applications/shortcut/README.md +128 -0
  211. universal_mcp/applications/shortcut/__init__.py +1 -0
  212. universal_mcp/applications/shortcut/app.py +4478 -0
  213. universal_mcp/applications/slack/README.md +0 -0
  214. universal_mcp/applications/slack/__init__.py +1 -0
  215. universal_mcp/applications/slack/app.py +570 -0
  216. universal_mcp/applications/spotify/README.md +91 -0
  217. universal_mcp/applications/spotify/__init__.py +1 -0
  218. universal_mcp/applications/spotify/app.py +2526 -0
  219. universal_mcp/applications/supabase/README.md +87 -0
  220. universal_mcp/applications/supabase/__init__.py +1 -0
  221. universal_mcp/applications/supabase/app.py +2970 -0
  222. universal_mcp/applications/tavily/README.md +12 -0
  223. universal_mcp/applications/tavily/__init__.py +1 -0
  224. universal_mcp/applications/tavily/app.py +51 -0
  225. universal_mcp/applications/trello/README.md +266 -0
  226. universal_mcp/applications/trello/__init__.py +1 -0
  227. universal_mcp/applications/trello/app.py +10875 -0
  228. universal_mcp/applications/twillo/README.md +0 -0
  229. universal_mcp/applications/twillo/__init__.py +1 -0
  230. universal_mcp/applications/twillo/app.py +269 -0
  231. universal_mcp/applications/twitter/README.md +100 -0
  232. universal_mcp/applications/twitter/__init__.py +1 -0
  233. universal_mcp/applications/twitter/api_segments/__init__.py +0 -0
  234. universal_mcp/applications/twitter/api_segments/api_segment_base.py +51 -0
  235. universal_mcp/applications/twitter/api_segments/compliance_api.py +122 -0
  236. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +255 -0
  237. universal_mcp/applications/twitter/api_segments/dm_events_api.py +140 -0
  238. universal_mcp/applications/twitter/api_segments/likes_api.py +159 -0
  239. universal_mcp/applications/twitter/api_segments/lists_api.py +395 -0
  240. universal_mcp/applications/twitter/api_segments/openapi_json_api.py +34 -0
  241. universal_mcp/applications/twitter/api_segments/spaces_api.py +309 -0
  242. universal_mcp/applications/twitter/api_segments/trends_api.py +40 -0
  243. universal_mcp/applications/twitter/api_segments/tweets_api.py +1403 -0
  244. universal_mcp/applications/twitter/api_segments/usage_api.py +40 -0
  245. universal_mcp/applications/twitter/api_segments/users_api.py +1498 -0
  246. universal_mcp/applications/twitter/app.py +46 -0
  247. universal_mcp/applications/unipile/README.md +28 -0
  248. universal_mcp/applications/unipile/__init__.py +1 -0
  249. universal_mcp/applications/unipile/app.py +829 -0
  250. universal_mcp/applications/whatsapp/README.md +23 -0
  251. universal_mcp/applications/whatsapp/__init__.py +1 -0
  252. universal_mcp/applications/whatsapp/app.py +595 -0
  253. universal_mcp/applications/whatsapp-business/README.md +34 -0
  254. universal_mcp/applications/whatsapp-business/__init__.py +1 -0
  255. universal_mcp/applications/whatsapp-business/app.py +1065 -0
  256. universal_mcp/applications/wrike/README.md +46 -0
  257. universal_mcp/applications/wrike/__init__.py +1 -0
  258. universal_mcp/applications/wrike/app.py +1583 -0
  259. universal_mcp/applications/youtube/README.md +57 -0
  260. universal_mcp/applications/youtube/__init__.py +1 -0
  261. universal_mcp/applications/youtube/app.py +1696 -0
  262. universal_mcp/applications/zenquotes/README.md +12 -0
  263. universal_mcp/applications/zenquotes/__init__.py +1 -0
  264. universal_mcp/applications/zenquotes/app.py +31 -0
  265. universal_mcp_applications-0.1.1.dist-info/METADATA +172 -0
  266. universal_mcp_applications-0.1.1.dist-info/RECORD +268 -0
  267. universal_mcp_applications-0.1.1.dist-info/WHEEL +4 -0
  268. universal_mcp_applications-0.1.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,20 @@
1
+ # FirecrawlApp MCP Server
2
+
3
+ An MCP Server for the FirecrawlApp API.
4
+
5
+ ## 🛠️ Tool List
6
+
7
+ This is automatically generated from OpenAPI schema for the FirecrawlApp API.
8
+
9
+
10
+ | Tool | Description |
11
+ |------|-------------|
12
+ | `scrape_url` | Scrapes a single URL using Firecrawl and returns the extracted data. |
13
+ | `search` | Performs a web search using Firecrawl's search capability. |
14
+ | `start_crawl` | Starts a async crawl job for a given URL using Firecrawl. Returns the job ID immediately. |
15
+ | `check_crawl_status` | Checks the status of a previously initiated async Firecrawl crawl job. |
16
+ | `cancel_crawl` | Cancels a currently running Firecrawl crawl job. |
17
+ | `start_batch_scrape` | Starts a batch scrape job for multiple URLs using Firecrawl. (Note: May map to multiple individual scrapes or a specific batch API endpoint if available) |
18
+ | `check_batch_scrape_status` | Checks the status of a previously initiated Firecrawl batch scrape job. |
19
+ | `quick_web_extract` | Performs a quick, synchronous extraction of data from one or more URLs using Firecrawl and returns the results directly. |
20
+ | `check_extract_status` | Checks the status of a previously initiated Firecrawl extraction job. |
@@ -0,0 +1 @@
1
+ from .app import FirecrawlApp
@@ -0,0 +1,514 @@
1
+ from typing import Any
2
+
3
+ from loguru import logger
4
+
5
+ try:
6
+ from firecrawl import Firecrawl
7
+
8
+ FirecrawlApiClient: type[Firecrawl] | None = Firecrawl
9
+ except ImportError:
10
+ FirecrawlApiClient = None
11
+
12
+ logger.error(
13
+ "Failed to import FirecrawlApp. Please ensure 'firecrawl-py' is installed."
14
+ )
15
+
16
+
17
+ from universal_mcp.applications.application import APIApplication
18
+ from universal_mcp.exceptions import NotAuthorizedError, ToolError
19
+ from universal_mcp.integrations import Integration
20
+
21
+
22
+ class FirecrawlApp(APIApplication):
23
+ """
24
+ Application for interacting with the Firecrawl service (firecrawl.dev)
25
+ to scrape web pages, perform searches, and manage crawl/batch scrape/extract jobs.
26
+ Requires a Firecrawl API key configured via integration.
27
+ Authentication is handled by the configured Integration, fetching the API key.
28
+ """
29
+
30
+ def __init__(self, integration: Integration | None = None, **kwargs: Any) -> None:
31
+ super().__init__(name="firecrawl", integration=integration, **kwargs)
32
+ self._firecrawl_api_key: str | None = None # Cache for the API key
33
+ if FirecrawlApiClient is None:
34
+ logger.warning(
35
+ "Firecrawl SDK is not available. Firecrawl tools will not function."
36
+ )
37
+
38
+ @property
39
+ def firecrawl_api_key(self) -> str:
40
+ """
41
+ Retrieves and caches the Firecrawl API key from the integration.
42
+ Raises NotAuthorizedError if the key cannot be obtained.
43
+ """
44
+ if self._firecrawl_api_key is None:
45
+ if not self.integration:
46
+ logger.error(
47
+ f"{self.name.capitalize()} App: Integration not configured."
48
+ )
49
+ raise NotAuthorizedError(
50
+ f"Integration not configured for {self.name.capitalize()} App. Cannot retrieve API key."
51
+ )
52
+
53
+ try:
54
+ credentials = self.integration.get_credentials()
55
+ except NotAuthorizedError as e:
56
+ logger.error(
57
+ f"{self.name.capitalize()} App: Authorization error when fetching credentials: {e.message}"
58
+ )
59
+ raise # Re-raise the original NotAuthorizedError
60
+ except Exception as e:
61
+ logger.error(
62
+ f"{self.name.capitalize()} App: Unexpected error when fetching credentials: {e}",
63
+ exc_info=True,
64
+ )
65
+ raise NotAuthorizedError(
66
+ f"Failed to get {self.name.capitalize()} credentials: {e}"
67
+ )
68
+
69
+ api_key = (
70
+ credentials.get("api_key")
71
+ or credentials.get("API_KEY") # Check common variations
72
+ or credentials.get("apiKey")
73
+ )
74
+
75
+ if not api_key:
76
+ logger.error(
77
+ f"{self.name.capitalize()} App: API key not found in credentials."
78
+ )
79
+ action_message = (
80
+ f"API key for {self.name.capitalize()} is missing. "
81
+ "Please ensure it's set in the store via MCP frontend or configuration."
82
+ )
83
+ if hasattr(self.integration, "authorize") and callable(
84
+ self.integration.authorize
85
+ ):
86
+ try:
87
+ auth_details = self.integration.authorize()
88
+ if isinstance(auth_details, str):
89
+ action_message = auth_details
90
+ elif isinstance(auth_details, dict) and "url" in auth_details:
91
+ action_message = (
92
+ f"Please authorize via: {auth_details['url']}"
93
+ )
94
+ elif (
95
+ isinstance(auth_details, dict) and "message" in auth_details
96
+ ):
97
+ action_message = auth_details["message"]
98
+ except Exception as auth_e:
99
+ logger.warning(
100
+ f"Could not retrieve specific authorization action for {self.name.capitalize()}: {auth_e}"
101
+ )
102
+ raise NotAuthorizedError(action_message)
103
+
104
+ self._firecrawl_api_key = api_key
105
+ logger.info(
106
+ f"{self.name.capitalize()} API Key successfully retrieved and cached."
107
+ )
108
+ assert self._firecrawl_api_key is not None
109
+ return self._firecrawl_api_key
110
+
111
+ def _get_client(self) -> Firecrawl:
112
+ """
113
+ Initializes and returns the Firecrawl client after ensuring API key is set.
114
+ Raises NotAuthorizedError if API key cannot be obtained or SDK is not installed.
115
+ """
116
+ if FirecrawlApiClient is None:
117
+ logger.error("Firecrawl SDK (firecrawl-py) is not available.")
118
+ raise ToolError(
119
+ "Firecrawl SDK (firecrawl-py) is not installed or failed to import."
120
+ )
121
+
122
+ # The property self.firecrawl_api_key will raise NotAuthorizedError if key is missing/unretrievable
123
+ current_api_key = self.firecrawl_api_key
124
+ return FirecrawlApiClient(api_key=current_api_key)
125
+
126
+ def _handle_firecrawl_exception(self, e: Exception, operation_desc: str) -> str:
127
+ """
128
+ Handles exceptions from Firecrawl operations, raising NotAuthorizedError for auth issues
129
+ and returning an error string for other issues.
130
+ This helper is designed to be used in tool methods.
131
+ """
132
+ logger.error(
133
+ f"Firecrawl App: Error during {operation_desc}: {type(e).__name__} - {e}",
134
+ exc_info=True,
135
+ )
136
+ # Check for common authentication/authorization indicators
137
+ error_str = str(e).lower()
138
+ is_auth_error = (
139
+ "unauthorized" in error_str
140
+ or "api key" in error_str
141
+ or "authentication" in error_str
142
+ or (
143
+ hasattr(e, "response")
144
+ and hasattr(e.response, "status_code")
145
+ and e.response.status_code == 401
146
+ ) # type: ignore
147
+ or (hasattr(e, "status_code") and e.status_code == 401) # type: ignore
148
+ )
149
+ if is_auth_error:
150
+ raise NotAuthorizedError(
151
+ f"Firecrawl API authentication/authorization failed for {operation_desc}: {e}"
152
+ )
153
+
154
+ return f"Error during {operation_desc}: {type(e).__name__} - {e}"
155
+
156
+ def scrape_url(self, url: str) -> Any:
157
+ """
158
+ Scrapes a single URL using Firecrawl and returns the extracted data.
159
+
160
+ Args:
161
+ url: The URL of the web page to scrape.
162
+
163
+ Returns:
164
+ A dictionary containing the scraped data on success,
165
+ or a string containing an error message on failure.
166
+
167
+ Raises:
168
+ NotAuthorizedError: If API key is missing or invalid.
169
+ ToolError: If the Firecrawl SDK is not installed.
170
+
171
+ Tags:
172
+ scrape, important
173
+ """
174
+ logger.info(f"Attempting to scrape URL: {url}")
175
+ try:
176
+ client = self._get_client()
177
+ response_data = client.scrape(url=url)
178
+ logger.info(f"Successfully scraped URL: {url}")
179
+ return response_data
180
+ except NotAuthorizedError:
181
+ raise
182
+ except ToolError:
183
+ raise
184
+ except Exception as e:
185
+ error_msg = self._handle_firecrawl_exception(e, f"scraping URL {url}")
186
+ return error_msg
187
+
188
+ def search(self, query: str) -> dict[str, Any] | str:
189
+ """
190
+ Performs a web search using Firecrawl's search capability.
191
+
192
+ Args:
193
+ query: The search query string.
194
+
195
+ Returns:
196
+ A dictionary containing the search results on success,
197
+ or a string containing an error message on failure.
198
+
199
+ Raises:
200
+ NotAuthorizedError: If API key is missing or invalid.
201
+ ToolError: If the Firecrawl SDK is not installed.
202
+
203
+ Tags:
204
+ search, important
205
+ """
206
+ logger.info(f"Attempting Firecrawl search for query: {query}")
207
+ try:
208
+ client = self._get_client()
209
+ response = client.search(query=query)
210
+ logger.info(f"Successfully performed Firecrawl search for query: {query}")
211
+ return response # type: ignore
212
+ except NotAuthorizedError:
213
+ raise
214
+ except ToolError:
215
+ raise
216
+ except Exception as e:
217
+ return self._handle_firecrawl_exception(e, f"search for '{query}'")
218
+
219
+ def start_crawl(
220
+ self,
221
+ url: str,
222
+ ) -> dict[str, Any] | str:
223
+ """
224
+ Starts a async crawl job for a given URL using Firecrawl. Returns the job ID immediately.
225
+
226
+ Args:
227
+ url: The starting URL for the crawl.
228
+
229
+ Returns:
230
+ A dictionary containing the job initiation response on success,
231
+ or a string containing an error message on failure.
232
+
233
+ Raises:
234
+ NotAuthorizedError: If API key is missing or invalid.
235
+ ToolError: If the Firecrawl SDK is not installed.
236
+
237
+ Tags:
238
+ crawl, async_job, start
239
+ """
240
+ logger.info(f"Attempting to start Firecrawl crawl for URL: {url}")
241
+ try:
242
+ client = self._get_client()
243
+ response = client.start_crawl(
244
+ url=url,
245
+ )
246
+ job_id = response.id
247
+ logger.info(
248
+ f"Successfully started Firecrawl crawl for URL {url}, Job ID: {job_id}"
249
+ )
250
+ return response # type: ignore
251
+ except NotAuthorizedError:
252
+ raise
253
+ except ToolError:
254
+ raise
255
+ except Exception as e:
256
+ return self._handle_firecrawl_exception(e, f"starting crawl for URL {url}") # type: ignore
257
+
258
+ def check_crawl_status(self, job_id: str) -> dict[str, Any] | str:
259
+ """
260
+ Checks the status of a previously initiated async Firecrawl crawl job.
261
+
262
+ Args:
263
+ job_id: The ID of the crawl job to check.
264
+
265
+ Returns:
266
+ A dictionary containing the job status details on success,
267
+ or a string containing an error message on failure.
268
+
269
+ Raises:
270
+ NotAuthorizedError: If API key is missing or invalid.
271
+ ToolError: If the Firecrawl SDK is not installed.
272
+
273
+ Tags:
274
+ crawl, async_job, status
275
+ """
276
+ logger.info(f"Attempting to check Firecrawl crawl status for job ID: {job_id}")
277
+ try:
278
+ client = self._get_client()
279
+ status = client.get_crawl_status(job_id=job_id)
280
+ logger.info(
281
+ f"Successfully checked Firecrawl crawl status for job ID: {job_id}"
282
+ )
283
+ return status # type: ignore
284
+ except NotAuthorizedError:
285
+ raise
286
+ except ToolError:
287
+ raise
288
+ except Exception as e:
289
+ return self._handle_firecrawl_exception(
290
+ e, f"checking crawl status for job ID {job_id}"
291
+ ) # type: ignore
292
+
293
+ def cancel_crawl(self, job_id: str) -> dict[str, Any] | str:
294
+ """
295
+ Cancels a currently running Firecrawl crawl job.
296
+
297
+ Args:
298
+ job_id: The ID of the crawl job to cancel.
299
+
300
+ Returns:
301
+ A dictionary confirming the cancellation status on success,
302
+ or a string containing an error message on failure.
303
+ (Note: This functionality might depend on Firecrawl API capabilities)
304
+
305
+ Raises:
306
+ NotAuthorizedError: If API key is missing or invalid.
307
+ ToolError: If the Firecrawl SDK is not installed or operation not supported.
308
+
309
+ Tags:
310
+ crawl, async_job, management, cancel
311
+ """
312
+ logger.info(f"Attempting to cancel Firecrawl crawl job ID: {job_id}")
313
+ try:
314
+ client = self._get_client()
315
+ response = client.cancel_crawl(crawl_id=job_id)
316
+ logger.info(
317
+ f"Successfully issued cancel command for Firecrawl crawl job ID: {job_id}"
318
+ )
319
+ return response # type: ignore
320
+ except NotAuthorizedError:
321
+ raise
322
+ except ToolError:
323
+ raise
324
+ except Exception as e:
325
+ return self._handle_firecrawl_exception(
326
+ e, f"cancelling crawl job ID {job_id}"
327
+ ) # type: ignore
328
+
329
+ def start_batch_scrape(
330
+ self,
331
+ urls: list[str],
332
+ ) -> dict[str, Any] | str:
333
+ """
334
+ Starts a batch scrape job for multiple URLs using Firecrawl. (Note: May map to multiple individual scrapes or a specific batch API endpoint if available)
335
+
336
+ Args:
337
+ urls: A list of URLs to scrape.
338
+
339
+ Returns:
340
+ A dictionary containing the job initiation response (e.g., a batch job ID or list of results/job IDs) on success,
341
+ or a string containing an error message on failure.
342
+
343
+ Raises:
344
+ NotAuthorizedError: If API key is missing or invalid.
345
+ ToolError: If the Firecrawl SDK is not installed.
346
+
347
+ Tags:
348
+ scrape, batch, async_job, start
349
+ """
350
+ logger.info(f"Attempting to start Firecrawl batch scrape for {len(urls)} URLs.")
351
+ try:
352
+ client = self._get_client()
353
+ response = client.start_batch_scrape(urls=urls)
354
+ logger.info(
355
+ f"Successfully started Firecrawl batch scrape for {len(urls)} URLs."
356
+ )
357
+ return response # type: ignore
358
+ except NotAuthorizedError:
359
+ raise
360
+ except ToolError:
361
+ raise
362
+ except Exception as e:
363
+ return self._handle_firecrawl_exception(
364
+ e, f"starting batch scrape for {len(urls)} URLs"
365
+ ) # type: ignore
366
+
367
+ def check_batch_scrape_status(self, job_id: str) -> dict[str, Any] | str:
368
+ """
369
+ Checks the status of a previously initiated Firecrawl batch scrape job.
370
+
371
+ Args:
372
+ job_id: The ID of the batch scrape job to check.
373
+
374
+ Returns:
375
+ A dictionary containing the job status details on success,
376
+ or a string containing an error message on failure.
377
+
378
+ Raises:
379
+ NotAuthorizedError: If API key is missing or invalid.
380
+ ToolError: If the Firecrawl SDK is not installed or operation not supported.
381
+
382
+ Tags:
383
+ scrape, batch, async_job, status
384
+ """
385
+ logger.info(
386
+ f"Attempting to check Firecrawl batch scrape status for job ID: {job_id}"
387
+ )
388
+ try:
389
+ client = self._get_client()
390
+ status = client.get_batch_scrape_status(job_id=job_id)
391
+ logger.info(
392
+ f"Successfully checked Firecrawl batch scrape status for job ID: {job_id}"
393
+ )
394
+ return status # type: ignore
395
+ except NotAuthorizedError:
396
+ raise
397
+ except ToolError:
398
+ raise
399
+ except Exception as e:
400
+ return self._handle_firecrawl_exception(
401
+ e, f"checking batch scrape status for job ID {job_id}"
402
+ ) # type: ignore
403
+
404
+ def quick_web_extract(
405
+ self,
406
+ urls: list[str],
407
+ prompt: str | None = None,
408
+ schema: Any | None = None,
409
+ system_prompt: str | None = None,
410
+ allow_external_links: bool | None = False,
411
+ ) -> dict[str, Any]:
412
+ """
413
+ Performs a quick, synchronous extraction of data from one or more URLs using Firecrawl and returns the results directly.
414
+
415
+ Args:
416
+ urls: A list of URLs to extract data from.
417
+ prompt: Optional custom extraction prompt describing what data to extract.
418
+ schema: Optional JSON schema or Pydantic model for the desired output structure.
419
+ system_prompt: Optional system context for the extraction.
420
+ allow_external_links: Optional boolean to allow following external links.
421
+
422
+ Returns:
423
+ A dictionary containing the extracted data on success.
424
+
425
+ Raises:
426
+ NotAuthorizedError: If API key is missing or invalid.
427
+ ToolError: If the Firecrawl SDK is not installed or extraction fails.
428
+
429
+ Tags:
430
+ extract, ai, sync, quick, important
431
+ """
432
+ logger.info(
433
+ f"Attempting quick web extraction for {len(urls)} URLs with prompt: {prompt is not None}, schema: {schema is not None}."
434
+ )
435
+ try:
436
+ client = self._get_client()
437
+ response = client.extract(
438
+ urls=urls,
439
+ prompt=prompt,
440
+ schema=schema,
441
+ system_prompt=system_prompt,
442
+ allow_external_links=allow_external_links,
443
+ )
444
+ logger.info(
445
+ f"Successfully completed quick web extraction for {len(urls)} URLs."
446
+ )
447
+ return response # type: ignore
448
+ except NotAuthorizedError:
449
+ logger.error("Firecrawl API key missing or invalid.")
450
+ raise
451
+ except ToolError:
452
+ logger.error("Firecrawl SDK not installed.")
453
+ raise
454
+ except Exception as e:
455
+ error_message = self._handle_firecrawl_exception(
456
+ e, f"quick web extraction for {len(urls)} URLs"
457
+ )
458
+ logger.error(f"Failed to perform quick web extraction: {error_message}")
459
+ if error_message:
460
+ raise ToolError(error_message)
461
+ else:
462
+ raise ToolError(
463
+ f"Quick web extraction failed for {len(urls)} URLs: {e}"
464
+ )
465
+
466
+ def check_extract_status(self, job_id: str) -> dict[str, Any] | str:
467
+ """
468
+ Checks the status of a previously initiated Firecrawl extraction job.
469
+
470
+ Args:
471
+ job_id: The ID of the extraction job to check.
472
+
473
+ Returns:
474
+ A dictionary containing the job status details on success,
475
+ or a string containing an error message on failure.
476
+
477
+ Raises:
478
+ NotAuthorizedError: If API key is missing or invalid.
479
+ ToolError: If the Firecrawl SDK is not installed or operation not supported.
480
+
481
+ Tags:
482
+ extract, ai, async_job, status
483
+ """
484
+ logger.info(
485
+ f"Attempting to check Firecrawl extraction status for job ID: {job_id}"
486
+ )
487
+ try:
488
+ client = self._get_client()
489
+ status = client.get_extract_status(job_id=job_id)
490
+ logger.info(
491
+ f"Successfully checked Firecrawl extraction status for job ID: {job_id}"
492
+ )
493
+ return status # type: ignore
494
+ except NotAuthorizedError:
495
+ raise
496
+ except ToolError:
497
+ raise
498
+ except Exception as e:
499
+ return self._handle_firecrawl_exception(
500
+ e, f"checking extraction status for job ID {job_id}"
501
+ ) # type: ignore
502
+
503
+ def list_tools(self):
504
+ return [
505
+ self.scrape_url,
506
+ self.search,
507
+ self.start_crawl,
508
+ self.check_crawl_status,
509
+ self.cancel_crawl,
510
+ self.start_batch_scrape,
511
+ self.check_batch_scrape_status,
512
+ self.quick_web_extract,
513
+ self.check_extract_status,
514
+ ]
@@ -0,0 +1,25 @@
1
+ # FirefliesApp MCP Server
2
+
3
+ An MCP Server for the FirefliesApp API.
4
+
5
+ ## 🛠️ Tool List
6
+
7
+ This is automatically generated from OpenAPI schema for the FirefliesApp API.
8
+
9
+
10
+ | Tool | Description |
11
+ |------|-------------|
12
+ | `get_team_analytics` | Fetches team analytics data within a specified time range. |
13
+ | `get_ai_apps_outputs` | Fetches AI Apps outputs for a given transcript. |
14
+ | `get_user_details` | Fetches details for a specific user. |
15
+ | `list_users` | Fetches a list of users in the workspace. |
16
+ | `get_transcript_details` | Fetches details for a specific transcript. |
17
+ | `list_transcripts` | Fetches a list of transcripts, optionally filtered by user ID. |
18
+ | `get_bite_details` | Fetches details for a specific bite (soundbite/clip). |
19
+ | `list_bites` | Fetches a list of bites, optionally filtered to the current user's bites. |
20
+ | `add_to_live_meeting` | Adds Fireflies.ai to a live meeting. |
21
+ | `create_bite` | Creates a bite (soundbite/clip) from a transcript. |
22
+ | `delete_transcript` | Deletes a transcript. |
23
+ | `set_user_role` | Sets the role for a user. |
24
+ | `upload_audio` | Uploads an audio file for transcription. |
25
+ | `update_meeting_title` | Updates the title of a meeting (transcript). |
@@ -0,0 +1 @@
1
+ from .app import FirefliesApp