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.
- 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 → serpapi}/app.py +11 -3
 - universal_mcp/applications/tavily/app.py +14 -4
 - universal_mcp/integrations/integration.py +4 -3
 - universal_mcp/servers/server.py +5 -2
 - universal_mcp/utils/installation.py +2 -2
 - {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8rc1.dist-info}/METADATA +2 -2
 - {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8rc1.dist-info}/RECORD +14 -14
 - /universal_mcp/applications/{serp → serpapi}/README.md +0 -0
 - {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8rc1.dist-info}/WHEEL +0 -0
 - {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8rc1.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:
         
     | 
| 
         @@ -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  
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
      
 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)
         
     | 
    
        universal_mcp/servers/server.py
    CHANGED
    
    | 
         @@ -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/", 
     | 
| 
      
 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" 
     | 
| 
      
 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. 
     | 
| 
      
 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 
     | 
| 
      
 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= 
     | 
| 
      
 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,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= 
     | 
| 
      
 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= 
     | 
| 
       34 
     | 
    
         
            -
            universal_mcp/applications/ 
     | 
| 
       35 
     | 
    
         
            -
            universal_mcp/applications/ 
     | 
| 
      
 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= 
     | 
| 
      
 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 
     | 
    
         
            -
            universal_mcp/servers/server.py,sha256= 
     | 
| 
      
 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= 
     | 
| 
      
 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.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
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |