-
Notifications
You must be signed in to change notification settings - Fork 781
Allow logger to also take URLs #451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,7 +6,7 @@ | |||||||||||||||||||
| import signal | ||||||||||||||||||||
| import sys | ||||||||||||||||||||
| from datetime import datetime, timezone | ||||||||||||||||||||
| from typing import Optional, Dict, Any, List | ||||||||||||||||||||
| from typing import Optional, Dict, Any, List, Union | ||||||||||||||||||||
| from urllib.parse import urlparse | ||||||||||||||||||||
|
|
||||||||||||||||||||
| import httpx | ||||||||||||||||||||
|
|
@@ -19,8 +19,9 @@ | |||||||||||||||||||
| from mcp_agent.cli.auth import load_credentials, UserCredentials | ||||||||||||||||||||
| from mcp_agent.cli.cloud.commands.utils import setup_authenticated_client | ||||||||||||||||||||
| from mcp_agent.cli.core.api_client import UnauthenticatedError | ||||||||||||||||||||
| from mcp_agent.cli.core.utils import parse_app_identifier, resolve_server_url | ||||||||||||||||||||
| from mcp_agent.cli.core.utils import run_async | ||||||||||||||||||||
| from mcp_agent.cli.utils.ux import print_error | ||||||||||||||||||||
| from mcp_agent.cli.mcp_app.api_client import MCPApp, MCPAppConfiguration | ||||||||||||||||||||
|
|
||||||||||||||||||||
| console = Console() | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
@@ -29,7 +30,7 @@ | |||||||||||||||||||
|
|
||||||||||||||||||||
| def tail_logs( | ||||||||||||||||||||
| app_identifier: str = typer.Argument( | ||||||||||||||||||||
| help="App ID or app configuration ID to retrieve logs for" | ||||||||||||||||||||
| help="App ID, app configuration ID, or server URL to retrieve logs for" | ||||||||||||||||||||
| ), | ||||||||||||||||||||
| since: Optional[str] = typer.Option( | ||||||||||||||||||||
| None, | ||||||||||||||||||||
|
|
@@ -91,6 +92,9 @@ def tail_logs( | |||||||||||||||||||
|
|
||||||||||||||||||||
| # Follow logs and filter for specific patterns | ||||||||||||||||||||
| mcp-agent cloud logger tail app_abc123 --follow --grep "authentication.*failed" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # Use server URL instead of app ID | ||||||||||||||||||||
| mcp-agent cloud logger tail https://abc123.mcpcloud.ai --follow | ||||||||||||||||||||
| """ | ||||||||||||||||||||
|
|
||||||||||||||||||||
| credentials = load_credentials() | ||||||||||||||||||||
|
|
@@ -130,14 +134,14 @@ def tail_logs( | |||||||||||||||||||
| print_error("--format must be 'text', 'json', or 'yaml'") | ||||||||||||||||||||
| raise typer.Exit(6) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| app_id, config_id = parse_app_identifier(app_identifier) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| client = setup_authenticated_client() | ||||||||||||||||||||
| server = run_async(client.get_app_or_config(app_identifier)) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| try: | ||||||||||||||||||||
| if follow: | ||||||||||||||||||||
| asyncio.run( | ||||||||||||||||||||
| _stream_logs( | ||||||||||||||||||||
| app_id=app_id, | ||||||||||||||||||||
| config_id=config_id, | ||||||||||||||||||||
| server=server, | ||||||||||||||||||||
| credentials=credentials, | ||||||||||||||||||||
| grep_pattern=grep, | ||||||||||||||||||||
| app_identifier=app_identifier, | ||||||||||||||||||||
|
|
@@ -147,16 +151,15 @@ def tail_logs( | |||||||||||||||||||
| else: | ||||||||||||||||||||
| asyncio.run( | ||||||||||||||||||||
| _fetch_logs( | ||||||||||||||||||||
| app_id=app_id, | ||||||||||||||||||||
| config_id=config_id, | ||||||||||||||||||||
| credentials=credentials, | ||||||||||||||||||||
| server=server, | ||||||||||||||||||||
| since=since, | ||||||||||||||||||||
| grep_pattern=grep, | ||||||||||||||||||||
| limit=limit, | ||||||||||||||||||||
| order_by=order_by, | ||||||||||||||||||||
| asc=asc, | ||||||||||||||||||||
| desc=desc, | ||||||||||||||||||||
| format=format, | ||||||||||||||||||||
| app_identifier=app_identifier, | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| ) | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
@@ -168,19 +171,26 @@ def tail_logs( | |||||||||||||||||||
|
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| async def _fetch_logs( | ||||||||||||||||||||
| app_id: Optional[str], | ||||||||||||||||||||
| config_id: Optional[str], | ||||||||||||||||||||
| credentials: UserCredentials, | ||||||||||||||||||||
| server: Union[MCPApp, MCPAppConfiguration], | ||||||||||||||||||||
| since: Optional[str], | ||||||||||||||||||||
| grep_pattern: Optional[str], | ||||||||||||||||||||
| limit: int, | ||||||||||||||||||||
| order_by: Optional[str], | ||||||||||||||||||||
| asc: bool, | ||||||||||||||||||||
| desc: bool, | ||||||||||||||||||||
| format: str, | ||||||||||||||||||||
| app_identifier: str, | ||||||||||||||||||||
| ) -> None: | ||||||||||||||||||||
| """Fetch logs one-time via HTTP API.""" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # Extract app_id and config_id from the server object | ||||||||||||||||||||
| if hasattr(server, 'appId'): # MCPApp | ||||||||||||||||||||
| app_id = server.appId | ||||||||||||||||||||
| config_id = None | ||||||||||||||||||||
| else: # MCPAppConfiguration | ||||||||||||||||||||
| app_id = None | ||||||||||||||||||||
| config_id = server.appConfigurationId | ||||||||||||||||||||
|
|
||||||||||||||||||||
| client = setup_authenticated_client() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # Map order_by parameter from CLI to API format | ||||||||||||||||||||
|
|
@@ -240,20 +250,23 @@ async def _fetch_logs( | |||||||||||||||||||
| console.print("[yellow]No logs found matching the criteria[/yellow]") | ||||||||||||||||||||
| return | ||||||||||||||||||||
|
|
||||||||||||||||||||
| _display_logs(filtered_logs, title=f"Logs for {app_id or config_id}", format=format) | ||||||||||||||||||||
| _display_logs(filtered_logs, title=f"Logs for {app_identifier}", format=format) | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| async def _stream_logs( | ||||||||||||||||||||
| app_id: Optional[str], | ||||||||||||||||||||
| config_id: Optional[str], | ||||||||||||||||||||
| server: Union[MCPApp, MCPAppConfiguration], | ||||||||||||||||||||
| credentials: UserCredentials, | ||||||||||||||||||||
| grep_pattern: Optional[str], | ||||||||||||||||||||
| app_identifier: str, | ||||||||||||||||||||
| format: str, | ||||||||||||||||||||
| ) -> None: | ||||||||||||||||||||
| """Stream logs continuously via SSE.""" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| server_url = await resolve_server_url(app_id, config_id, credentials) | ||||||||||||||||||||
| # Get server URL directly from the server object | ||||||||||||||||||||
| if not server.appServerInfo or not server.appServerInfo.serverUrl: | ||||||||||||||||||||
| raise CLIError("Server URL not available - server may not be deployed") | ||||||||||||||||||||
|
|
||||||||||||||||||||
| server_url = server.appServerInfo.serverUrl | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
Comment on lines
+265
to
270
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Harden server URL handling; add connect timeout for SSE.
- if not server.appServerInfo or not server.appServerInfo.serverUrl:
+ if not getattr(server, "appServerInfo", None) or not server.appServerInfo.serverUrl:
raise CLIError("Server URL not available - server may not be deployed")
-
- server_url = server.appServerInfo.serverUrl
+ server_url = server.appServerInfo.serverUrl.rstrip("/")Additional changes outside this hunk to complete the fix: - parsed = urlparse(server_url)
- stream_url = f"{parsed.scheme}://{parsed.netloc}/logs"
+ parsed = urlparse(server_url)
+ base_path = (parsed.path or "").rstrip("/")
+ stream_url = f"{parsed.scheme}://{parsed.netloc}{base_path}/logs"
- hostname = parsed.hostname or ""
- deployment_id = hostname.split(".")[0] if "." in hostname else hostname
+ hostname = (parsed.hostname or "").strip()
+ deployment_id = hostname.split(".", 1)[0] if hostname else ""And for the client (outside this hunk): - async with httpx.AsyncClient(timeout=None) as client:
+ async with httpx.AsyncClient(timeout=httpx.Timeout(connect=10.0, read=None)) as client:📝 Committable suggestion
Suggested change
|
||||||||||||||||||||
| parsed = urlparse(server_url) | ||||||||||||||||||||
| stream_url = f"{parsed.scheme}://{parsed.netloc}/logs" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -12,7 +12,6 @@ | |||||
| from mcp_agent.mcp.gen_client import gen_client | ||||||
| from ...utils import ( | ||||||
| setup_authenticated_client, | ||||||
| resolve_server, | ||||||
| handle_server_api_errors, | ||||||
| ) | ||||||
|
|
||||||
|
|
@@ -25,7 +24,7 @@ async def _cancel_workflow_async( | |||||
| server_url = server_id_or_url | ||||||
| else: | ||||||
| client = setup_authenticated_client() | ||||||
| server = resolve_server(client, server_id_or_url) | ||||||
| server = run_async(client.get_app_or_config(server_id_or_url)) | ||||||
|
|
||||||
|
Comment on lines
+27
to
28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: run_async used inside async function Await instead. - server = run_async(client.get_app_or_config(server_id_or_url))
+ server = await client.get_app_or_config(server_id_or_url)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| if hasattr(server, "appServerInfo") and server.appServerInfo: | ||||||
| server_url = server.appServerInfo.serverUrl | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -14,7 +14,6 @@ | |||||
| from mcp_agent.mcp.gen_client import gen_client | ||||||
| from ...utils import ( | ||||||
| setup_authenticated_client, | ||||||
| resolve_server, | ||||||
| handle_server_api_errors, | ||||||
| ) | ||||||
|
|
||||||
|
|
@@ -27,7 +26,7 @@ async def _describe_workflow_async( | |||||
| server_url = server_id_or_url | ||||||
| else: | ||||||
| client = setup_authenticated_client() | ||||||
| server = resolve_server(client, server_id_or_url) | ||||||
| server = run_async(client.get_app_or_config(server_id_or_url)) | ||||||
|
|
||||||
|
Comment on lines
+29
to
30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: run_async used inside async function Await instead. - server = run_async(client.get_app_or_config(server_id_or_url))
+ server = await client.get_app_or_config(server_id_or_url)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| if hasattr(server, "appServerInfo") and server.appServerInfo: | ||||||
| server_url = server.appServerInfo.serverUrl | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -15,7 +15,6 @@ | |||||
| from mcp_agent.mcp.gen_client import gen_client | ||||||
| from ...utils import ( | ||||||
| setup_authenticated_client, | ||||||
| resolve_server, | ||||||
| handle_server_api_errors, | ||||||
| validate_output_format, | ||||||
| ) | ||||||
|
|
@@ -27,7 +26,7 @@ async def _list_workflows_async(server_id_or_url: str, format: str = "text") -> | |||||
| server_url = server_id_or_url | ||||||
| else: | ||||||
| client = setup_authenticated_client() | ||||||
| server = resolve_server(client, server_id_or_url) | ||||||
| server = run_async(client.get_app_or_config(server_id_or_url)) | ||||||
|
|
||||||
|
Comment on lines
+29
to
30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: run_async used inside async function This will fail under a running event loop. Await the coroutine instead. - server = run_async(client.get_app_or_config(server_id_or_url))
+ server = await client.get_app_or_config(server_id_or_url)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| if hasattr(server, "appServerInfo") and server.appServerInfo: | ||||||
| server_url = server.appServerInfo.serverUrl | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -13,7 +13,6 @@ | |||||
| from mcp_agent.mcp.gen_client import gen_client | ||||||
| from ...utils import ( | ||||||
| setup_authenticated_client, | ||||||
| resolve_server, | ||||||
| handle_server_api_errors, | ||||||
| ) | ||||||
|
|
||||||
|
|
@@ -29,7 +28,7 @@ async def _signal_workflow_async( | |||||
| server_url = server_id_or_url | ||||||
| else: | ||||||
| client = setup_authenticated_client() | ||||||
| server = resolve_server(client, server_id_or_url) | ||||||
| server = run_async(client.get_app_or_config(server_id_or_url)) | ||||||
|
|
||||||
|
Comment on lines
+31
to
32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: run_async used inside async function Await instead. - server = run_async(client.get_app_or_config(server_id_or_url))
+ server = await client.get_app_or_config(server_id_or_url)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| if hasattr(server, "appServerInfo") and server.appServerInfo: | ||||||
| server_url = server.appServerInfo.serverUrl | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -14,7 +14,6 @@ | |||||
| from ...utils import ( | ||||||
| setup_authenticated_client, | ||||||
| validate_output_format, | ||||||
| resolve_server, | ||||||
| ) | ||||||
| from mcp_agent.cli.utils.ux import console, print_info | ||||||
|
|
||||||
|
|
@@ -27,7 +26,7 @@ async def _list_workflow_runs_async( | |||||
| server_url = server_id_or_url | ||||||
| else: | ||||||
| client = setup_authenticated_client() | ||||||
| server = resolve_server(client, server_id_or_url) | ||||||
| server = run_async(client.get_app_or_config(server_id_or_url)) | ||||||
|
|
||||||
|
Comment on lines
+29
to
30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: run_async used inside async function Await instead. - server = run_async(client.get_app_or_config(server_id_or_url))
+ server = await client.get_app_or_config(server_id_or_url)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| if hasattr(server, "appServerInfo") and server.appServerInfo: | ||||||
| server_url = server.appServerInfo.serverUrl | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Catch resolution errors: wrap get_app_or_config in the existing try.
Right now, failures raise before the try/except and bypass clean CLIError formatting.
Optional (outside this hunk): add specific excepts for httpx.HTTPStatusError (401/404) around this try to mirror _fetch_logs.
📝 Committable suggestion
🤖 Prompt for AI Agents