universal-mcp 0.1.7rc1__py3-none-any.whl → 0.1.8rc1__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.
@@ -25,11 +25,18 @@ class E2BApp(APIApplication):
25
25
  credentials = self.integration.get_credentials()
26
26
  if not credentials:
27
27
  raise ValueError(
28
- f"Failed to retrieve E2B API Key using integration '{self.integration.name}'. "
29
- f"Check store configuration (e.g., ensure the correct environment variable is set)."
28
+ f"Invalid credential format received for E2B API Key via integration '{self.integration.name}'. "
30
29
  )
31
-
32
- self.api_key = credentials
30
+ api_key = (
31
+ credentials.get("api_key")
32
+ or credentials.get("API_KEY")
33
+ or credentials.get("apiKey")
34
+ )
35
+ if not api_key:
36
+ raise ValueError(
37
+ f"Invalid credential format received for E2B API Key via integration '{self.integration.name}'. "
38
+ )
39
+ self.api_key = api_key
33
40
  logger.info("E2B API Key successfully retrieved via integration.")
34
41
 
35
42
  def _format_execution_output(self, logs) -> str:
@@ -26,9 +26,7 @@ class FirecrawlApp(APIApplication):
26
26
  return
27
27
 
28
28
  if not self.integration:
29
- raise ValueError(
30
- "Integration is None. Cannot retrieve Firecrawl API Key."
31
- )
29
+ raise ValueError("Integration is None. Cannot retrieve Firecrawl API Key.")
32
30
 
33
31
  credentials = self.integration.get_credentials()
34
32
  if not credentials:
@@ -36,9 +34,18 @@ class FirecrawlApp(APIApplication):
36
34
  f"Failed to retrieve Firecrawl API Key using integration '{self.integration.name}'. "
37
35
  f"Check store configuration (e.g., ensure the correct source like environment variable is set)."
38
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
39
48
 
40
- self.api_key = credentials
41
-
42
49
  def _get_client(self) -> FirecrawlApiClient:
43
50
  """Initializes and returns the Firecrawl client after ensuring API key is set."""
44
51
  self._set_api_key()
@@ -128,9 +135,9 @@ class FirecrawlApp(APIApplication):
128
135
  """
129
136
  try:
130
137
  client = self._get_client()
131
- status = client.check_crawl_status(id=job_id)
138
+ status = client.check_crawl_status(id=job_id)
132
139
  return status
133
-
140
+
134
141
  except Exception as e:
135
142
  return f"Error checking crawl status for job ID {job_id}: {type(e).__name__} - {e}"
136
143
 
@@ -148,13 +155,12 @@ class FirecrawlApp(APIApplication):
148
155
  try:
149
156
  client = self._get_client()
150
157
  response = client.cancel_crawl(id=job_id)
151
-
158
+
152
159
  return response
153
160
 
154
- except Exception as e:
161
+ except Exception as e:
155
162
  return f"Error cancelling crawl job ID {job_id}: {type(e).__name__} - {e}"
156
163
 
157
-
158
164
  def start_batch_scrape(
159
165
  self,
160
166
  urls: list[str],
@@ -196,9 +202,9 @@ class FirecrawlApp(APIApplication):
196
202
  """
197
203
  try:
198
204
  client = self._get_client()
199
- status = client.check_batch_scrape_status(id=job_id)
205
+ status = client.check_batch_scrape_status(id=job_id)
200
206
  return status
201
-
207
+
202
208
  except Exception as e:
203
209
  return f"Error checking batch scrape status for job ID {job_id}: {type(e).__name__} - {e}"
204
210
 
@@ -220,7 +226,7 @@ class FirecrawlApp(APIApplication):
220
226
  A dictionary containing the job initiation response on success,
221
227
  or a string containing an error message on failure.
222
228
  """
223
-
229
+
224
230
  try:
225
231
  client = self._get_client()
226
232
  response = client.async_extract(
@@ -246,7 +252,7 @@ class FirecrawlApp(APIApplication):
246
252
  client = self._get_client()
247
253
  status = client.get_extract_status(job_id=job_id)
248
254
  return status
249
-
255
+
250
256
  except Exception as e:
251
257
  return f"Error checking extraction status for job ID {job_id}: {type(e).__name__} - {e}"
252
258
 
@@ -262,4 +268,4 @@ class FirecrawlApp(APIApplication):
262
268
  self.check_batch_scrape_status,
263
269
  self.start_extract,
264
270
  self.check_extract_status,
265
- ]
271
+ ]
@@ -19,16 +19,20 @@ class PerplexityApp(APIApplication):
19
19
  raise ValueError("Integration is None. Cannot retrieve Perplexity API Key.")
20
20
 
21
21
  credentials = self.integration.get_credentials()
22
- if not credentials or "apiKey" not in credentials:
22
+ if not credentials:
23
23
  raise ValueError(
24
24
  f"Failed to retrieve Perplexity API Key using integration '{self.integration.name}'. "
25
25
  )
26
-
27
- # if not isinstance(credentials, str) or not credentials.strip():
28
- # raise ValueError(
29
- # f"Invalid credential format received for Perplexity API Key via integration '{self.integration.name}'. "
30
- # )
31
- self.api_key = credentials["apiKey"]
26
+ api_key = (
27
+ credentials.get("api_key")
28
+ or credentials.get("API_KEY")
29
+ or credentials.get("apiKey")
30
+ )
31
+ if not api_key:
32
+ raise ValueError(
33
+ f"Invalid credential format received for Perplexity API Key via integration '{self.integration.name}'. "
34
+ )
35
+ self.api_key = api_key
32
36
 
33
37
  def _get_headers(self) -> dict[str, str]:
34
38
  self._set_api_key()
@@ -5,13 +5,23 @@ from universal_mcp.integrations import Integration
5
5
  class ResendApp(APIApplication):
6
6
  def __init__(self, integration: Integration) -> None:
7
7
  super().__init__(name="resend", integration=integration)
8
+ self.api_key = None
8
9
 
9
10
  def _get_headers(self):
10
- credentials = self.integration.get_credentials()
11
- if not credentials:
12
- raise ValueError("No credentials found")
11
+ if not self.api_key:
12
+ credentials = self.integration.get_credentials()
13
+ if not credentials:
14
+ raise ValueError("No credentials found")
15
+ api_key = (
16
+ credentials.get("api_key")
17
+ or credentials.get("API_KEY")
18
+ or credentials.get("apiKey")
19
+ )
20
+ if not api_key:
21
+ raise ValueError("No API key found")
22
+ self.api_key = api_key
13
23
  return {
14
- "Authorization": f"Bearer {credentials['api_key']}",
24
+ "Authorization": f"Bearer {self.api_key}",
15
25
  }
16
26
 
17
27
  def send_email(self, to: str, subject: str, content: str) -> str:
@@ -5,7 +5,7 @@ from serpapi import SerpApiClient as SerpApiSearch
5
5
  from universal_mcp.applications.application import APIApplication
6
6
 
7
7
 
8
- class SerpApp(APIApplication):
8
+ class SerpapiApp(APIApplication):
9
9
  def __init__(self, **kwargs):
10
10
  super().__init__(name="serpapi", **kwargs)
11
11
  self.api_key: str | None = None
@@ -22,8 +22,16 @@ class SerpApp(APIApplication):
22
22
  f"Failed to retrieve SERP API Key using integration '{self.integration.name}'. "
23
23
  f"Check store configuration (e.g., ensure the correct environment variable is set)."
24
24
  )
25
-
26
- self.api_key = credentials
25
+ api_key = (
26
+ credentials.get("api_key")
27
+ or credentials.get("API_KEY")
28
+ or credentials.get("apiKey")
29
+ )
30
+ if not api_key:
31
+ raise ValueError(
32
+ f"Invalid credential format received for SERP API Key via integration '{self.integration.name}'. "
33
+ )
34
+ self.api_key = api_key
27
35
  logger.info("SERP API Key successfully retrieved via integration.")
28
36
 
29
37
  async def search(self, params: dict[str, any] = None) -> str:
@@ -7,13 +7,23 @@ class TavilyApp(APIApplication):
7
7
  name = "tavily"
8
8
  self.base_url = "https://api.tavily.com"
9
9
  super().__init__(name=name, integration=integration)
10
+ self.api_key = None
10
11
 
11
12
  def _get_headers(self):
12
- credentials = self.integration.get_credentials()
13
- if not credentials:
14
- raise ValueError("No credentials found")
13
+ if not self.api_key:
14
+ credentials = self.integration.get_credentials()
15
+ if not credentials:
16
+ raise ValueError("No credentials found")
17
+ api_key = (
18
+ credentials.get("api_key")
19
+ or credentials.get("API_KEY")
20
+ or credentials.get("apiKey")
21
+ )
22
+ if not api_key:
23
+ raise ValueError("No API key found")
24
+ self.api_key = api_key
15
25
  return {
16
- "Authorization": f"Bearer {credentials['api_key']}",
26
+ "Authorization": f"Bearer {self.api_key}",
17
27
  "Content-Type": "application/json",
18
28
  }
19
29
 
@@ -8,12 +8,13 @@ from universal_mcp.stores.store import Store
8
8
 
9
9
 
10
10
  def sanitize_api_key_name(name: str) -> str:
11
- suffix = "_API_KEY"
11
+ suffix = "_API_KEY"
12
12
  if name.endswith(suffix) or name.endswith(suffix.lower()):
13
13
  return name.upper()
14
14
  else:
15
15
  return f"{name.upper()}{suffix}"
16
-
16
+
17
+
17
18
  class Integration(ABC):
18
19
  """Abstract base class for handling application integrations and authentication.
19
20
 
@@ -91,7 +92,7 @@ class ApiKeyIntegration(Integration):
91
92
  if credentials is None:
92
93
  action = self.authorize()
93
94
  raise NotAuthorizedError(action)
94
- return credentials
95
+ return {"api_key": credentials}
95
96
 
96
97
  def set_credentials(self, credentials: dict):
97
98
  self.store.set(self.name, credentials)
@@ -140,6 +140,7 @@ class AgentRServer(Server):
140
140
  super().__init__(name, description=description, **kwargs)
141
141
 
142
142
  def _load_app(self, app_config: AppConfig):
143
+ logger.info(f"Loading app: {app_config}")
143
144
  name = app_config.name
144
145
  if app_config.integration:
145
146
  integration_name = app_config.integration.name
@@ -152,12 +153,14 @@ class AgentRServer(Server):
152
153
  def _list_apps_with_integrations(self) -> list[AppConfig]:
153
154
  # TODO: get this from the API
154
155
  response = httpx.get(
155
- f"{self.base_url}/api/apps/", headers={"X-API-KEY": self.api_key}
156
+ f"{self.base_url}/api/apps/",
157
+ headers={"X-API-KEY": self.api_key},
158
+ timeout=10,
156
159
  )
157
160
  response.raise_for_status()
158
161
  apps = response.json()
159
162
 
160
- logger.info(f"Apps: {apps}")
163
+ logger.info(f"Loaded apps: {apps}")
161
164
  return [AppConfig.model_validate(app) for app in apps]
162
165
 
163
166
  def _load_apps(self):
@@ -61,7 +61,7 @@ def install_claude(api_key: str) -> None:
61
61
  config["mcpServers"] = {}
62
62
  config["mcpServers"]["universal_mcp"] = {
63
63
  "command": get_uvx_path(),
64
- "args": ["universal_mcp@latest", "run"],
64
+ "args": ["universal_mcp[all]@latest", "run"],
65
65
  "env": {"AGENTR_API_KEY": api_key},
66
66
  }
67
67
  with open(config_path, "w") as f:
@@ -90,7 +90,7 @@ def install_cursor(api_key: str) -> None:
90
90
  config["mcpServers"] = {}
91
91
  config["mcpServers"]["universal_mcp"] = {
92
92
  "command": get_uvx_path(),
93
- "args": ["universal_mcp@latest", "run"],
93
+ "args": ["universal_mcp[all]@latest", "run"],
94
94
  "env": {"AGENTR_API_KEY": api_key},
95
95
  }
96
96
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp
3
- Version: 0.1.7rc1
3
+ Version: 0.1.8rc1
4
4
  Summary: Universal MCP acts as a middle ware for your API applications. It can store your credentials, authorize, enable disable apps on the fly and much more.
5
5
  Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
6
6
  Requires-Python: >=3.11
@@ -25,7 +25,7 @@ Requires-Dist: e2b-code-interpreter>=1.2.0; extra == 'e2b'
25
25
  Provides-Extra: firecrawl
26
26
  Requires-Dist: firecrawl-py>=1.15.0; extra == 'firecrawl'
27
27
  Provides-Extra: markitdown
28
- Requires-Dist: markitdown[all,e2b]>=0.1.1; extra == 'markitdown'
28
+ Requires-Dist: markitdown[all]>=0.1.1; extra == 'markitdown'
29
29
  Provides-Extra: playground
30
30
  Requires-Dist: fastapi[standard]>=0.115.12; extra == 'playground'
31
31
  Requires-Dist: langchain-anthropic>=0.3.10; extra == 'playground'
@@ -7,9 +7,9 @@ universal_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  universal_mcp/applications/__init__.py,sha256=qeWnbdIudyMR7ST4XTc0gpEM9o6TsM1ZnZ92dMAPSBA,754
8
8
  universal_mcp/applications/application.py,sha256=dqp8lgIi2xhY62imwo7C6769URQtNmqd6Ok6PiTr6wc,3399
9
9
  universal_mcp/applications/e2b/README.md,sha256=S4lTp-vEZ8VTCKPXqjUXu5nYlUMAF8lw8CQyBGPgxjs,700
10
- universal_mcp/applications/e2b/app.py,sha256=dC6TFhN9NYzZqmJno47ZCU01Un7M3HlqNxuXx7UEOso,2733
10
+ universal_mcp/applications/e2b/app.py,sha256=l7oRmxIuVglA1v9EtYqx_rlvYjUZz7GShmI_VLEQLjI,2979
11
11
  universal_mcp/applications/firecrawl/README.md,sha256=KAWe_TQbrc9eA6bSyde5dapMP1CNvarVItV_YJH3d_0,1430
12
- universal_mcp/applications/firecrawl/app.py,sha256=RSy8zRn4k1A1tIpJNqrUnPI8ctEv1nKWuOuJQcp9mGo,9264
12
+ universal_mcp/applications/firecrawl/app.py,sha256=aPYx3uCsrR6CHz0RERE0ikHMbzwbhKE-SDkF5DVZLiQ,9572
13
13
  universal_mcp/applications/github/README.md,sha256=6ID-__gUJ5ZxzAS_OjzmoUAag1LamSvEB75DHcj3m-g,1294
14
14
  universal_mcp/applications/github/app.py,sha256=L201f5MSx1YVx0nqgduZ5gyHPZdX0UfcEhPmDWiWK6s,13686
15
15
  universal_mcp/applications/google_calendar/app.py,sha256=g_3vrsM2ltwpTySgC5I4SYg47n4UJiYigECO0ax1EHM,19134
@@ -26,23 +26,23 @@ universal_mcp/applications/notion/README.md,sha256=45NmPOmSQv99qBvWdwmnV5vbaYc9_
26
26
  universal_mcp/applications/notion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  universal_mcp/applications/notion/app.py,sha256=XpLnmeXj0Gnf_RYHlbAFnwtSCTYsrNzk6MSMSyDmHGQ,17283
28
28
  universal_mcp/applications/perplexity/README.md,sha256=QGV1iReH5p-Np7vvkZsVHxxDKQ0YaitHEwomNmGEyQs,732
29
- universal_mcp/applications/perplexity/app.py,sha256=81cR_UUyBlAzonq0GsSuV6w2XxLsKIiMelJDc8h5Fxw,3444
29
+ universal_mcp/applications/perplexity/app.py,sha256=q3FUnSHwq-_HnIUTYuxVdKmNJ5p0b-Aj3vZ0ZrP7Mg4,3494
30
30
  universal_mcp/applications/reddit/README.md,sha256=YVbJ1RN6NWlB-P6w2LxCk_DuUWl7mwaKZScY-mIMnNc,1271
31
31
  universal_mcp/applications/reddit/app.py,sha256=leU__w5VxX1vMK-kfuy-dvY97Pn8Mn80X2payVshirU,13562
32
32
  universal_mcp/applications/resend/README.md,sha256=k-sb2UwbFvDPEz6qQPLWd2cJj8hDx5f3NW7dz2jAfjI,719
33
- universal_mcp/applications/resend/app.py,sha256=bRo-CRDuk65EUSHOJnbVHWV6TuiUHtedz6FXKRS1ym0,1386
34
- universal_mcp/applications/serp/README.md,sha256=hX4VeT2iL_67ZsMhKd60DAujQCh9K3IdHroHIq808RY,691
35
- universal_mcp/applications/serp/app.py,sha256=hPXu1sBiRZRCCzr4q2uvt54F0-B3aZK2Uz4wfKokkZ4,3131
33
+ universal_mcp/applications/resend/app.py,sha256=fl_0U61Rm0fqz1lCxPiuGRkl2x0meafp6kMZbshD7wo,1733
34
+ universal_mcp/applications/serpapi/README.md,sha256=hX4VeT2iL_67ZsMhKd60DAujQCh9K3IdHroHIq808RY,691
35
+ universal_mcp/applications/serpapi/app.py,sha256=r4V8lty348X5hGQyP4DfG89hHRI68SnxYd6sFgTBjcY,3464
36
36
  universal_mcp/applications/tavily/README.md,sha256=cNg4EwX5wBbkDpPtNBNC3A_GxglfSVhdAJuweSrXN20,721
37
- universal_mcp/applications/tavily/app.py,sha256=FSIRFz7jwm2i9wiDpRWIoQBxHaJ6dl89AjSZY9WP2VE,1776
37
+ universal_mcp/applications/tavily/app.py,sha256=K5TLh6OSQ7w792poupZidzgbWotrIyEsu7YnGzPRX0w,2123
38
38
  universal_mcp/applications/zenquotes/README.md,sha256=wA3hjqjrkrczQaffpwyolSKq6gXmkLgeHx6_EQrYEOY,709
39
39
  universal_mcp/applications/zenquotes/app.py,sha256=nidRGwVORIU25QGCCbjDIv1UNFUj5nWA3qqK4JP0Tdg,621
40
40
  universal_mcp/integrations/README.md,sha256=lTAPXO2nivcBe1q7JT6PRa6v9Ns_ZersQMIdw-nmwEA,996
41
41
  universal_mcp/integrations/__init__.py,sha256=8e11JZyctaR9CmlNkfEZ6HhGDvhlvf9iug2wdjb5pwY,270
42
42
  universal_mcp/integrations/agentr.py,sha256=l0mo79oeDML19udFfoCo9lyhbDAf0X94_lnpOgbTrb0,3331
43
- universal_mcp/integrations/integration.py,sha256=8TYr7N1F6oV8PPOSLo0eA_6nD-vrwIWbuplqwD03uuQ,5819
43
+ universal_mcp/integrations/integration.py,sha256=X8COgD8vg1bKUq4-0ytkMytk1eEaDF1O2JLvu3ewgFk,5828
44
44
  universal_mcp/servers/__init__.py,sha256=dgRW_khG537GeLKC5_U5jhxCuu1L_1YeTujeDg0601E,654
45
- universal_mcp/servers/server.py,sha256=9GazpAzNiMgCMg4Vb4VeyoviddEt6pQzi7vLli8vC5A,6677
45
+ universal_mcp/servers/server.py,sha256=iVyb_4KM3S6ppjDhWAnUdo0B8qugmnVe9utneUYJUgA,6771
46
46
  universal_mcp/stores/__init__.py,sha256=Sc4AWtee_qtK5hpEVUAH2XM_6EBhcfikQXWiGXdNfes,560
47
47
  universal_mcp/stores/store.py,sha256=CNOnmKeOCkSU2ZA9t12AIWJcmqZZX_LSyZaV8FQf8Xk,4545
48
48
  universal_mcp/utils/__init__.py,sha256=8wi4PGWu-SrFjNJ8U7fr2iFJ1ktqlDmSKj1xYd7KSDc,41
@@ -50,9 +50,9 @@ universal_mcp/utils/api_generator.py,sha256=-wRBpLVfJQXy1R-8FpDNs6b8_eeekVDuPc_u
50
50
  universal_mcp/utils/bridge.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  universal_mcp/utils/docgen.py,sha256=yK6Ijo8G-wHPU3E1AnFpnXS9vXt2j9FM77w0etTaNOA,12639
52
52
  universal_mcp/utils/dump_app_tools.py,sha256=cLB9SumKsbs-rXJ_02lpMyyNkOmKZ57gekhCjhAlcHg,2009
53
- universal_mcp/utils/installation.py,sha256=uSL_H76fG_7yN4QNxkfp1mEF_00iAPyiXqtdWEMVJe8,3747
53
+ universal_mcp/utils/installation.py,sha256=3vy9ZLjQj1xpSAOyWpOanBr7o5DtffzWB5JAjN0Jjtk,3757
54
54
  universal_mcp/utils/openapi.py,sha256=ud_ZB7_60BcS1Vao7ESKDqo0gry9JN5wzy-CFssrjm8,13140
55
- universal_mcp-0.1.7rc1.dist-info/METADATA,sha256=mwq5fSI-AWh4t7sJXfgooEnhI19wmVeD75uPjutsboI,10855
56
- universal_mcp-0.1.7rc1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
57
- universal_mcp-0.1.7rc1.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
58
- universal_mcp-0.1.7rc1.dist-info/RECORD,,
55
+ universal_mcp-0.1.8rc1.dist-info/METADATA,sha256=aIw8d3MEmmQdznN6OagpdSAMxLVaCPPJgCpbqxSkw3U,10851
56
+ universal_mcp-0.1.8rc1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
57
+ universal_mcp-0.1.8rc1.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
58
+ universal_mcp-0.1.8rc1.dist-info/RECORD,,
File without changes