universal-mcp 0.1.7rc1__py3-none-any.whl → 0.1.7rc2__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/applications/e2b/app.py +11 -4
- universal_mcp/applications/firecrawl/app.py +21 -15
- universal_mcp/applications/perplexity/app.py +11 -7
- universal_mcp/applications/resend/app.py +14 -4
- universal_mcp/applications/serp/app.py +10 -2
- universal_mcp/applications/tavily/app.py +14 -4
- universal_mcp/integrations/integration.py +4 -3
- universal_mcp/utils/installation.py +2 -2
- {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.7rc2.dist-info}/METADATA +1 -1
- {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.7rc2.dist-info}/RECORD +12 -12
- {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.7rc2.dist-info}/WHEEL +0 -0
- {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.7rc2.dist-info}/entry_points.txt +0 -0
@@ -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"
|
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
|
-
|
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
|
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
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
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 {
|
24
|
+
"Authorization": f"Bearer {self.api_key}",
|
15
25
|
}
|
16
26
|
|
17
27
|
def send_email(self, to: str, subject: str, content: str) -> str:
|
@@ -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
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
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 {
|
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)
|
@@ -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.
|
3
|
+
Version: 0.1.7rc2
|
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
|
@@ -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=
|
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=
|
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,21 +26,21 @@ 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=
|
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=
|
33
|
+
universal_mcp/applications/resend/app.py,sha256=fl_0U61Rm0fqz1lCxPiuGRkl2x0meafp6kMZbshD7wo,1733
|
34
34
|
universal_mcp/applications/serp/README.md,sha256=hX4VeT2iL_67ZsMhKd60DAujQCh9K3IdHroHIq808RY,691
|
35
|
-
universal_mcp/applications/serp/app.py,sha256=
|
35
|
+
universal_mcp/applications/serp/app.py,sha256=ug-XkyRrWRRgO_DV_lw4kIzQaGREd5VW1vV4Xv3ptAc,3461
|
36
36
|
universal_mcp/applications/tavily/README.md,sha256=cNg4EwX5wBbkDpPtNBNC3A_GxglfSVhdAJuweSrXN20,721
|
37
|
-
universal_mcp/applications/tavily/app.py,sha256=
|
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=
|
43
|
+
universal_mcp/integrations/integration.py,sha256=X8COgD8vg1bKUq4-0ytkMytk1eEaDF1O2JLvu3ewgFk,5828
|
44
44
|
universal_mcp/servers/__init__.py,sha256=dgRW_khG537GeLKC5_U5jhxCuu1L_1YeTujeDg0601E,654
|
45
45
|
universal_mcp/servers/server.py,sha256=9GazpAzNiMgCMg4Vb4VeyoviddEt6pQzi7vLli8vC5A,6677
|
46
46
|
universal_mcp/stores/__init__.py,sha256=Sc4AWtee_qtK5hpEVUAH2XM_6EBhcfikQXWiGXdNfes,560
|
@@ -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=
|
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.
|
56
|
-
universal_mcp-0.1.
|
57
|
-
universal_mcp-0.1.
|
58
|
-
universal_mcp-0.1.
|
55
|
+
universal_mcp-0.1.7rc2.dist-info/METADATA,sha256=p5lVC89uhzjoZVt6ltqWNKdwpLljzROvssQRJAXrVu0,10855
|
56
|
+
universal_mcp-0.1.7rc2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
57
|
+
universal_mcp-0.1.7rc2.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
|
58
|
+
universal_mcp-0.1.7rc2.dist-info/RECORD,,
|
File without changes
|
File without changes
|