Skip to content

Conversation

@jtcorbett
Copy link
Contributor

@jtcorbett jtcorbett commented Sep 5, 2025

TL;DR

Added workflow management commands to the MCP Agent CLI, including describe, suspend, resume, and cancel operations.

What changed?

  • Added four new workflow management commands:
    • describe_workflow: Shows detailed information about a workflow execution
    • suspend_workflow: Pauses a running workflow execution
    • resume_workflow: Resumes a previously suspended workflow
    • cancel_workflow: Permanently stops a workflow execution
  • Implemented corresponding API client methods in WorkflowAPIClient:
    • suspend_workflow
    • resume_workflow
    • cancel_workflow
  • Updated the CLI structure to expose these commands under mcp-agent cloud workflows
  • Added an alias for describe_workflow as status for backward compatibility

How to test?

Test the new workflow commands with a running workflow:

# Get workflow details
mcp-agent cloud workflows describe run_abc123
mcp-agent cloud workflows status run_abc123  # alias

# Suspend a workflow
mcp-agent cloud workflows suspend run_abc123

# Resume a workflow (with optional payload)
mcp-agent cloud workflows resume run_abc123
mcp-agent cloud workflows resume run_abc123 --payload '{"data": "value"}'

# Cancel a workflow (with optional reason)
mcp-agent cloud workflows cancel run_abc123
mcp-agent cloud workflows cancel run_abc123 --reason "User requested cancellation"

Why make this change?

These commands provide essential workflow lifecycle management capabilities to users, allowing them to monitor and control workflow executions through the CLI. The ability to suspend, resume, and cancel workflows gives users more control over long-running operations and helps manage resources more efficiently.

Summary by CodeRabbit

  • New Features

    • Added a new "workflows" CLI group with describe (alias: status), resume, suspend, and cancel commands; describe supports text, JSON, and YAML output and accepts server ID or URL.
  • Refactor

    • Reorganized CLI wiring from singular "workflow" to plural "workflows" and consolidated command registrations.
    • Adjusted internal imports for utilities (no behavioral changes).
  • Chores

    • Removed legacy workflow status package-level re-exports and updated module descriptions.

@coderabbitai
Copy link

coderabbitai bot commented Sep 5, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Refactors several utility import paths, updates a utils docstring, removes the legacy single workflow status CLI and its re-exports, and adds a pluralized workflows CLI group with new describe, resume, suspend, and cancel command implementations plus package-level exports; updates cloud CLI wiring and one logger import.

Changes

Cohort / File(s) Summary of changes
Utility import path refactor
src/mcp_agent/cli/cloud/commands/logger/tail/main.py, src/mcp_agent/cli/cloud/commands/servers/delete/main.py, src/mcp_agent/cli/cloud/commands/servers/describe/main.py, src/mcp_agent/cli/cloud/commands/servers/list/main.py
Adjusted relative imports to import shared helpers from .../commands/utils (path changes only; imported names unchanged).
Utils docstring update
src/mcp_agent/cli/cloud/commands/utils.py
Docstring updated from “Shared utilities for server commands.” to “Shared utilities for cloud commands.” (no behavior change).
Remove legacy workflow status command and re-exports
src/mcp_agent/cli/cloud/commands/workflow/__init__.py, src/mcp_agent/cli/cloud/commands/workflow/status/__init__.py, src/mcp_agent/cli/cloud/commands/workflow/status/main.py
Deleted package initializer, status subpackage init, and the Typer-based get_workflow_status command implementation; package-level re-export of get_workflow_status removed.
Add new workflows package exports
src/mcp_agent/cli/cloud/commands/workflows/__init__.py, src/mcp_agent/cli/cloud/commands/workflows/describe/__init__.py, src/mcp_agent/cli/cloud/commands/workflows/resume/__init__.py, src/mcp_agent/cli/cloud/commands/workflows/cancel/__init__.py
Added package initializers that re-export workflow commands (describe_workflow, resume_workflow, suspend_workflow, cancel_workflow) and set __all__.
New workflows command implementations
src/mcp_agent/cli/cloud/commands/workflows/describe/main.py, src/mcp_agent/cli/cloud/commands/workflows/resume/main.py, src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py
Added Typer commands to describe workflow runs and to signal resume/suspend and cancel via MCP tool calls over SSE; include server resolution (ID or URL), authenticated client setup, MCPApp registration, gen_client calls, result parsing, formatted output, and CLIError handling.
Cloud CLI wiring updates
src/mcp_agent/cli/cloud/main.py
Replaced singular workflow group with plural workflows Typer group (renamed internal variable to app_cmd_workflows) and registered new subcommands: describe (alias status), resume, suspend, and cancel.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant CLI as cloud.workflows.describe
  participant Utils as Auth/Resolve
  participant MCP as MCPApp/Client
  participant Server as Workflow Server (SSE)

  User->>CLI: mcp-agent cloud workflows describe <server|url> <run_id>
  CLI->>Utils: setup_authenticated_client / resolve_server (if ID)
  alt Input is URL
    CLI->>Server: Derive SSE endpoint (/sse)
  else Input is Server ID
    Utils-->>CLI: serverUrl from appServerInfo
    CLI->>Server: Build SSE endpoint (/sse)
  end
  CLI->>MCP: init app + register server
  CLI->>MCP: gen_client("workflow_server")
  CLI->>Server: call tool "workflows-get_status" { run_id }
  Server-->>CLI: status payload
  CLI-->>User: Print status (text/json/yaml)
Loading
sequenceDiagram
  autonumber
  participant User
  participant CLI as cloud.workflows.cancel
  participant Utils as Auth/Resolve
  participant MCP as MCPApp/Client
  participant Server as Workflow Server (SSE)

  User->>CLI: mcp-agent cloud workflows cancel <server|url> <run_id> [--reason]
  CLI->>Utils: setup_authenticated_client / resolve_server
  CLI->>MCP: init app + register SSE server
  CLI->>Server: call tool "workflows-cancel" { run_id }
  Server-->>CLI: result.success (text/bool)
  alt success
    CLI-->>User: Print confirmation with Run ID (+ reason)
  else failure
    CLI-->>User: CLIError
  end
Loading
sequenceDiagram
  autonumber
  participant User
  participant CLI as cloud.workflows.resume/suspend
  participant Utils as Auth/Resolve
  participant MCP as MCPApp/Client
  participant Server as Workflow Server (SSE)

  User->>CLI: ... workflows (resume|suspend) <server|url> <run_id> [--payload]
  CLI->>Utils: setup_authenticated_client / resolve_server
  CLI->>MCP: init app + register SSE server
  CLI->>Server: call tool "workflows-resume" { run_id, signal=(resume|suspend), payload? }
  Server-->>CLI: result.success
  CLI-->>User: Success or CLIError
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Add Cloud Logger Commands to CLI #416 — Touches the logger tail command and related utils import adjustments; likely overlaps with the logger import change here.
  • Add cloud servers #420 — Related utilities refactor that relocates shared helpers; import path changes in this PR align with that refactor.
  • Move CLI from lmai repo #392 — Prior CLI restructuring around workflow/status modules; this PR continues that reorganization by removing legacy status and adding pluralized workflows.

Suggested reviewers

  • rholinshead
  • saqadri
  • petersonbill64

Poem

I hop through code with eager paws,
Plural workflows, new command laws.
Describe and cancel, resume, suspend—
I nibble imports, stitch each end.
A tidy CLI, my tiny applause. 🐰✨


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a07045 and d0f0d96.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • src/mcp_agent/cli/cloud/commands/logger/tail/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/servers/delete/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/servers/describe/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/servers/list/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/utils.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflow/__init__.py (0 hunks)
  • src/mcp_agent/cli/cloud/commands/workflow/status/__init__.py (0 hunks)
  • src/mcp_agent/cli/cloud/commands/workflow/status/main.py (0 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/__init__.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/cancel/__init__.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/describe/__init__.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/describe/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/resume/__init__.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/resume/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/main.py (3 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 09-05-add_workflow_commands_to_cli

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jtcorbett jtcorbett mentioned this pull request Sep 5, 2025
Copy link
Contributor Author

jtcorbett commented Sep 5, 2025

@jtcorbett jtcorbett force-pushed the 09-05-add_workflow_commands_to_cli branch from b703ddf to 964b3ed Compare September 5, 2025 20:54
@jtcorbett jtcorbett force-pushed the 09-05-do_not_allow_unsupported_server_urls_as_arguments branch 2 times, most recently from 6456278 to edc93a2 Compare September 5, 2025 21:15
@jtcorbett jtcorbett force-pushed the 09-05-add_workflow_commands_to_cli branch 3 times, most recently from fe4bb49 to 1b139f7 Compare September 5, 2025 21:28
@jtcorbett jtcorbett force-pushed the 09-05-do_not_allow_unsupported_server_urls_as_arguments branch from 897130c to 0998161 Compare September 5, 2025 21:28
@jtcorbett jtcorbett changed the base branch from 09-05-do_not_allow_unsupported_server_urls_as_arguments to graphite-base/424 September 5, 2025 21:37
@jtcorbett jtcorbett force-pushed the 09-05-add_workflow_commands_to_cli branch from 1b139f7 to 6a1876e Compare September 5, 2025 23:31
@jtcorbett jtcorbett changed the base branch from graphite-base/424 to 09-05-do_not_allow_unsupported_server_urls_as_arguments September 5, 2025 23:31
@jtcorbett jtcorbett changed the base branch from 09-05-do_not_allow_unsupported_server_urls_as_arguments to graphite-base/424 September 5, 2025 23:31
@jtcorbett jtcorbett force-pushed the 09-05-add_workflow_commands_to_cli branch from 6a1876e to 621e33c Compare September 8, 2025 19:14
@jtcorbett jtcorbett changed the base branch from graphite-base/424 to main September 8, 2025 19:14
@jtcorbett jtcorbett marked this pull request as ready for review September 8, 2025 19:15
@jtcorbett jtcorbett force-pushed the 09-05-add_workflow_commands_to_cli branch from 6e6696c to 50eaf6f Compare September 8, 2025 19:19
@jtcorbett jtcorbett force-pushed the 09-05-add_workflow_commands_to_cli branch from 48c65a9 to 2a07045 Compare September 8, 2025 20:35
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/mcp_agent/cli/cloud/commands/servers/list/main.py (1)

148-155: Fix created_at sorting to avoid aware/naive datetime comparison

Current key may mix timezone-aware datetimes with a naive fallback, causing TypeError and silently disabling sorting. Use a numeric key.

-        elif sort_field_lower in ['created', 'created_at', 'date']:
-            return created_at or datetime.min.replace(tzinfo=None if created_at is None else created_at.tzinfo)
+        elif sort_field_lower in ['created', 'created_at', 'date']:
+            # Use epoch seconds; None sorts first
+            try:
+                return created_at.timestamp() if created_at else float('-inf')
+            except Exception:
+                return float('-inf')
🧹 Nitpick comments (12)
src/mcp_agent/cli/cloud/commands/utils.py (1)

1-1: Align wording with broader "cloud" scope

Update messages/docstrings to avoid “servers”-specific phrasing now that this module backs logger/workflows too.

@@
-        raise CLIError(
-            "Must be logged in to access servers. Run 'mcp-agent login'."
-        )
+        raise CLIError(
+            "Must be logged in to access cloud resources. Run 'mcp-agent login'."
+        )
@@
-def handle_server_api_errors(func):
-    """Decorator to handle common API errors for server commands.
+def handle_server_api_errors(func):
+    """Decorator to handle common API errors for cloud commands.

Also applies to: 29-36, 81-89

src/mcp_agent/cli/cloud/commands/workflows/resume/__init__.py (1)

1-5: Split suspend into its own package for symmetry

Re-exporting suspend from the resume package can be confusing. Mirror the other commands for discoverability.

-"""MCP Agent Cloud workflow resume and suspend commands."""
-
-from .main import resume_workflow, suspend_workflow
-
-__all__ = ["resume_workflow", "suspend_workflow"]
+"""MCP Agent Cloud workflow resume command."""
+
+from .main import resume_workflow
+
+__all__ = ["resume_workflow"]

New file to add (for clarity and symmetry):

# src/mcp_agent/cli/cloud/commands/workflows/suspend/__init__.py
"""MCP Agent Cloud workflow suspend command."""
from ..resume.main import suspend_workflow  # or move implementation alongside this package
__all__ = ["suspend_workflow"]

Remember to update the aggregator (workflows/init.py) and CLI wiring accordingly.

src/mcp_agent/cli/cloud/commands/workflows/resume/main.py (3)

53-57: Result parsing is brittle; handle JSON/boolean content robustly

Assuming text “true” is narrow. Prefer checking JSON content or booleans, then text fallback.

-                success = result.content[0].text if result.content else False
-                if isinstance(success, str):
-                    success = success.lower() == 'true'
+                success = False
+                if result.content:
+                    item = result.content[0]
+                    # Prefer JSON/boolean content if present
+                    if hasattr(item, "data"):
+                        data = getattr(item, "data")
+                        success = bool(data.get("success", data)) if isinstance(data, dict) else bool(data)
+                    elif hasattr(item, "text"):
+                        txt = item.text.strip().lower()
+                        success = txt in {"true", "ok", "1", "success"}

Also applies to: 60-63


93-99: Use parsed JSON payload instead of discarding it

You detect JSON but don’t use it; send a typed object when possible.

     if payload:
         try:
-            json.loads(payload)
+            payload = json.loads(payload)
             console.print("[dim]Resuming with JSON payload...[/dim]")
         except json.JSONDecodeError:
             console.print("[dim]Resuming with text payload...[/dim]")

119-125: Mirror payload parsing for suspend

Same improvement as resume.

     if payload:
         try:
-            json.loads(payload)
+            payload = json.loads(payload)
             console.print("[dim]Suspending with JSON payload...[/dim]")
         except json.JSONDecodeError:
             console.print("[dim]Suspending with text payload...[/dim]")
src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py (3)

43-49: Tighten server tool surface (allow-list the cancel tool)

Limit exposed tools for this transient client to just what’s needed.

Apply:

             context.server_registry.registry["workflow_server"] = MCPServerSettings(
                 name="workflow_server",
                 description=f"Deployed MCP server {server_url}",
                 url=sse_url,
-                transport="sse"
+                transport="sse",
+                allowed_tools={"workflows-cancel"},
             )

60-65: UX: success should be green, not a warning

Minor polish.

Apply:

-                    console.print("[yellow]⚠[/yellow] Successfully cancelled workflow")
+                    console.print("[green]✅[/green] Successfully cancelled workflow")

22-35: DRY: extract shared server URL + SSE helpers

Both workflows commands duplicate server URL resolution and SSE URL shaping. Consider adding to .../utils.py:

Example helpers (outside this file):

def resolve_server_url_or_raise(server_id_or_url: str) -> str:
    if server_id_or_url.startswith(("http://", "https://")):
        return server_id_or_url
    client = setup_authenticated_client()
    server = resolve_server(client, server_id_or_url)
    server_url = getattr(getattr(server, "appServerInfo", None), "serverUrl", None)
    if not server_url:
        raise CLIError(f"Server '{server_id_or_url}' is not deployed or has no server URL")
    return server_url

def ensure_sse_url(server_url: str) -> str:
    return f"{server_url.rstrip('/')}/sse" if not server_url.endswith("/sse") else server_url

Then here:

server_url = resolve_server_url_or_raise(server_id_or_url)
sse_url = ensure_sse_url(server_url)

Also applies to: 43-43

src/mcp_agent/cli/cloud/commands/workflows/describe/main.py (4)

47-52: Limit exposed tools to only status tool

Reduce blast radius for the ad-hoc client.

Apply:

             context.server_registry.registry["workflow_server"] = MCPServerSettings(
                 name="workflow_server",
                 description=f"Deployed MCP server {server_url}",
                 url=sse_url,
-                transport="sse"
+                transport="sse",
+                allowed_tools={"workflows-get_status"},
             )

66-73: Avoid shadowing built-in 'format' and use safe YAML dump

Rename variable to output_format and switch to yaml.safe_dump.

Apply:

-    format: str = "text"
+    output_format: str = "text"
@@
-                if format == "json":
+                if output_format == "json":
                     print(json.dumps(workflow_status, indent=2))
-                elif format == "yaml":
-                    print(yaml.dump(workflow_status, default_flow_style=False))
+                elif output_format == "yaml":
+                    print(yaml.safe_dump(workflow_status, default_flow_style=False))
                 else:  # text format
                     print_workflow_status(workflow_status)
@@
-def describe_workflow(
+def describe_workflow(
     server_id_or_url: str = typer.Argument(..., help="Server ID or URL hosting the workflow"),
     run_id: str = typer.Argument(..., help="Run ID of the workflow to describe"),
-    format: Optional[str] = typer.Option("text", "--format", help="Output format (text|json|yaml)"),
+    output_format: Optional[str] = typer.Option("text", "--format", help="Output format (text|json|yaml)"),
 ) -> None:
@@
-    if format not in ["text", "json", "yaml"]:
+    if output_format not in ["text", "json", "yaml"]:
         console.print("[red]Error: --format must be 'text', 'json', or 'yaml'[/red]")
         raise typer.Exit(6)
 
-    run_async(_describe_workflow_async(server_id_or_url, run_id, format))
+    run_async(_describe_workflow_async(server_id_or_url, run_id, output_format))

Also applies to: 79-83, 92-96, 96-96


106-113: Include timezone when formatting Created time

Current output drops TZ info. Normalize to UTC and indicate it explicitly.

Apply:

-            from datetime import datetime
+            from datetime import datetime, timezone
             created_dt = datetime.fromisoformat(created_at.replace('Z', '+00:00'))
-            created_at = created_dt.strftime('%Y-%m-%d %H:%M:%S')
+            if created_dt.tzinfo is not None:
+                created_dt = created_dt.astimezone(tz=timezone.utc)
+            created_at = created_dt.strftime('%Y-%m-%d %H:%M:%S UTC')

39-41: DRY: reuse shared helpers for URL resolution and SSE shaping

Same duplication as in cancel command; see suggested utils in that comment.

Would simplify to:

server_url = resolve_server_url_or_raise(server_id_or_url)
sse_url = ensure_sse_url(server_url)

Also applies to: 43-54

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 130672d and 2a07045.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • src/mcp_agent/cli/cloud/commands/logger/tail/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/servers/delete/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/servers/describe/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/servers/list/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/utils.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflow/__init__.py (0 hunks)
  • src/mcp_agent/cli/cloud/commands/workflow/status/__init__.py (0 hunks)
  • src/mcp_agent/cli/cloud/commands/workflow/status/main.py (0 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/__init__.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/cancel/__init__.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/describe/__init__.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/describe/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/resume/__init__.py (1 hunks)
  • src/mcp_agent/cli/cloud/commands/workflows/resume/main.py (1 hunks)
  • src/mcp_agent/cli/cloud/main.py (3 hunks)
💤 Files with no reviewable changes (3)
  • src/mcp_agent/cli/cloud/commands/workflow/init.py
  • src/mcp_agent/cli/cloud/commands/workflow/status/init.py
  • src/mcp_agent/cli/cloud/commands/workflow/status/main.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-22T18:59:49.368Z
Learnt from: CR
PR: lastmile-ai/mcp-agent#0
File: examples/usecases/reliable_conversation/CLAUDE.md:0-0
Timestamp: 2025-07-22T18:59:49.368Z
Learning: Applies to examples/usecases/reliable_conversation/examples/reliable_conversation/src/utils/config.py : Configuration values such as quality_threshold, max_refinement_attempts, consolidation_interval, and evaluator_model_provider must be loaded from mcp_agent.config.yaml.

Applied to files:

  • src/mcp_agent/cli/cloud/commands/servers/describe/main.py
🧬 Code graph analysis (9)
src/mcp_agent/cli/cloud/commands/workflows/resume/__init__.py (1)
src/mcp_agent/cli/cloud/commands/workflows/resume/main.py (2)
  • resume_workflow (78-100)
  • suspend_workflow (104-126)
src/mcp_agent/cli/cloud/commands/logger/tail/main.py (1)
src/mcp_agent/cli/cloud/commands/utils.py (1)
  • setup_authenticated_client (18-36)
src/mcp_agent/cli/cloud/commands/workflows/__init__.py (4)
src/mcp_agent/cli/cloud/commands/workflows/describe/main.py (1)
  • describe_workflow (78-96)
src/mcp_agent/cli/cloud/commands/workflows/resume/main.py (2)
  • resume_workflow (78-100)
  • suspend_workflow (104-126)
src/mcp_agent/executor/workflow.py (1)
  • cancel (403-424)
src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py (1)
  • cancel_workflow (73-87)
src/mcp_agent/cli/cloud/commands/workflows/describe/main.py (4)
src/mcp_agent/cli/exceptions.py (1)
  • CLIError (4-9)
src/mcp_agent/config.py (2)
  • MCPServerSettings (52-113)
  • LoggerSettings (531-576)
src/mcp_agent/mcp/gen_client.py (1)
  • gen_client (16-41)
src/mcp_agent/cli/cloud/commands/utils.py (3)
  • setup_authenticated_client (18-36)
  • resolve_server (53-77)
  • handle_server_api_errors (80-105)
src/mcp_agent/cli/cloud/commands/workflows/cancel/__init__.py (1)
src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py (1)
  • cancel_workflow (73-87)
src/mcp_agent/cli/cloud/commands/workflows/describe/__init__.py (1)
src/mcp_agent/cli/cloud/commands/workflows/describe/main.py (1)
  • describe_workflow (78-96)
src/mcp_agent/cli/cloud/commands/workflows/resume/main.py (4)
src/mcp_agent/cli/exceptions.py (1)
  • CLIError (4-9)
src/mcp_agent/config.py (2)
  • MCPServerSettings (52-113)
  • LoggerSettings (531-576)
src/mcp_agent/mcp/gen_client.py (1)
  • gen_client (16-41)
src/mcp_agent/cli/cloud/commands/utils.py (3)
  • setup_authenticated_client (18-36)
  • resolve_server (53-77)
  • handle_server_api_errors (80-105)
src/mcp_agent/cli/cloud/main.py (3)
src/mcp_agent/cli/cloud/commands/workflows/describe/main.py (1)
  • describe_workflow (78-96)
src/mcp_agent/cli/cloud/commands/workflows/resume/main.py (2)
  • resume_workflow (78-100)
  • suspend_workflow (104-126)
src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py (1)
  • cancel_workflow (73-87)
src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py (5)
src/mcp_agent/cli/exceptions.py (1)
  • CLIError (4-9)
src/mcp_agent/app.py (2)
  • config (154-155)
  • logger (190-207)
src/mcp_agent/config.py (2)
  • MCPServerSettings (52-113)
  • LoggerSettings (531-576)
src/mcp_agent/mcp/gen_client.py (1)
  • gen_client (16-41)
src/mcp_agent/cli/cloud/commands/utils.py (3)
  • setup_authenticated_client (18-36)
  • resolve_server (53-77)
  • handle_server_api_errors (80-105)
🔇 Additional comments (13)
src/mcp_agent/cli/cloud/commands/logger/tail/main.py (1)

20-20: Import path realignment — OK

Switched to the centralized cloud utils; no behavior change.

src/mcp_agent/cli/cloud/commands/servers/list/main.py (1)

11-16: Import path update — OK

Utilities now sourced from the centralized cloud utils module.

src/mcp_agent/cli/cloud/commands/servers/describe/main.py (1)

10-16: Import path update — OK

Consistent with the centralized cloud utils module.

src/mcp_agent/cli/cloud/commands/servers/delete/main.py (1)

9-14: Import path update — OK

Centralized utils import looks correct; call sites unchanged.

src/mcp_agent/cli/cloud/commands/workflows/describe/__init__.py (1)

1-5: Package export — OK — alias verified
Re-exports are clean; public surface is explicit, and the status alias is correctly wired in src/mcp_agent/cli/cloud/main.py (lines 151–152).

src/mcp_agent/cli/cloud/commands/workflows/cancel/__init__.py (1)

1-5: Package export — OK

Docstring + explicit all are good.

src/mcp_agent/cli/cloud/commands/workflows/__init__.py (1)

3-12: Clean exports and grouping look good

Centralizing the command exports here is clear and consistent with the new workflows group. No issues.

src/mcp_agent/cli/cloud/commands/workflows/resume/main.py (2)

58-59: No change needed: CLI resume command correctly calls the only registered tool
Server code registers only workflows-resume via @mcp.tool(name="workflows-resume"); there is no workflows-suspend or generic workflows-signal tool to call.

Likely an incorrect or invalid review comment.


45-51: Remove headers propagation suggestion
The AppServerInfo model doesn’t include a headers field, so referencing server.appServerInfo.headers will not compile.

Likely an incorrect or invalid review comment.

src/mcp_agent/cli/cloud/main.py (2)

145-155: Workflows group wiring looks correct

New Typer group and command registrations (describe/status/resume/suspend/cancel) are consistent and discoverable.


212-214: Nice: workflows attached under cloud with clear help

Good placement and help text. No action needed.

src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py (1)

54-54: Remove verification check: workflows-cancel is already registered via @mcp.tool(name="workflows-cancel") in src/mcp_agent/server/app_server.py.

src/mcp_agent/cli/cloud/commands/workflows/describe/main.py (1)

55-58: No issues found: “workflows-get_status” is registered and SSE URL handling is consistent
The @mcp.tool decorator in src/mcp_agent/server/app_server.py registers workflows-get_status, and other workflow commands correctly use server_url.rstrip('/') for SSE URLs.

Comment on lines +52 to +55
tool_params = {"run_id": run_id}

result = await client.call_tool("workflows-cancel", tool_params)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix: forward --reason to server tool call

The CLI accepts --reason but doesn’t forward it, so the server never receives it.

Apply:

-                tool_params = {"run_id": run_id}
+                tool_params = {"run_id": run_id}
+                if reason is not None:
+                    tool_params["reason"] = reason
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tool_params = {"run_id": run_id}
result = await client.call_tool("workflows-cancel", tool_params)
tool_params = {"run_id": run_id}
if reason is not None:
tool_params["reason"] = reason
result = await client.call_tool("workflows-cancel", tool_params)
🤖 Prompt for AI Agents
In src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py around lines 52 to
55, the CLI parses a --reason flag but doesn’t include it in the payload sent to
the server; update the tool_params construction to include the reason (e.g., add
"reason": reason or conditionally add when reason is not None) so the await
client.call_tool("workflows-cancel", tool_params) forwards the reason to the
server.

Comment on lines +56 to +59
success = result.content[0].text if result.content else False
if isinstance(success, str):
success = success.lower() == 'true'

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden tool response parsing (accept bool/JSON/text “ok”)

Parsing assumes a text "true". Make it robust to boolean or JSON payloads.

Apply:

-                success = result.content[0].text if result.content else False
-                if isinstance(success, str):
-                    success = success.lower() == 'true'
+                success = False
+                if result.content:
+                    item = result.content[0]
+                    payload = getattr(item, "json", None) or getattr(item, "data", None) or getattr(item, "text", None)
+                    if isinstance(payload, dict) and "success" in payload:
+                        success = bool(payload["success"])
+                    elif isinstance(payload, str):
+                        success = payload.strip().lower() in {"true", "ok", "success", "1", "yes"}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +68 to +69
except Exception as e:
raise CLIError(f"Error cancelling workflow with run ID {run_id}: {str(e)}") from e
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Preserve CLIError semantics (avoid double-wrapping)

Re-raise CLIError as-is so exit codes/messages are preserved.

Apply:

-    except Exception as e:
-        raise CLIError(f"Error cancelling workflow with run ID {run_id}: {str(e)}") from e
+    except CLIError:
+        raise
+    except Exception as e:
+        raise CLIError(f"Error cancelling workflow with run ID {run_id}: {e}") from e
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except Exception as e:
raise CLIError(f"Error cancelling workflow with run ID {run_id}: {str(e)}") from e
except CLIError:
raise
except Exception as e:
raise CLIError(f"Error cancelling workflow with run ID {run_id}: {e}") from e
🤖 Prompt for AI Agents
In src/mcp_agent/cli/cloud/commands/workflows/cancel/main.py around lines 68-69,
the except block rewraps every Exception into a new CLIError which double-wraps
existing CLIError instances; change the handler to check if the caught exception
is already a CLIError and re-raise it unchanged (raise e), otherwise wrap
non-CLIError exceptions with CLIError(f"Error cancelling workflow with run ID
{run_id}: {str(e)}") from e so exit codes/messages are preserved.

Comment on lines +46 to +52
sse_url = f"{server_url}/sse" if not server_url.endswith('/sse') else server_url
context.server_registry.registry["workflow_server"] = MCPServerSettings(
name="workflow_server",
description=f"Deployed MCP server {server_url}",
url=sse_url,
transport="sse"
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

BUG: potential double slash in SSE URL

server_url like "https://host/" becomes "https://host//sse". Use rstrip('/') as done in cancel command.

Apply:

-            sse_url = f"{server_url}/sse" if not server_url.endswith('/sse') else server_url
+            sse_url = f"{server_url.rstrip('/')}/sse" if not server_url.endswith('/sse') else server_url
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sse_url = f"{server_url}/sse" if not server_url.endswith('/sse') else server_url
context.server_registry.registry["workflow_server"] = MCPServerSettings(
name="workflow_server",
description=f"Deployed MCP server {server_url}",
url=sse_url,
transport="sse"
)
sse_url = f"{server_url.rstrip('/')}/sse" if not server_url.endswith('/sse') else server_url
context.server_registry.registry["workflow_server"] = MCPServerSettings(
name="workflow_server",
description=f"Deployed MCP server {server_url}",
url=sse_url,
transport="sse"
)
🤖 Prompt for AI Agents
In src/mcp_agent/cli/cloud/commands/workflows/describe/main.py around lines 46
to 52, the SSE URL construction can produce a double slash when server_url ends
with '/', so normalize server_url first using rstrip('/') and then build sse_url
from that normalized value (only append "/sse" if the normalized string does not
already end with "/sse") — mirror the same normalization used in the cancel
command to avoid duplicated slashes.

Comment on lines +59 to +63
workflow_status = result.content[0].text if result.content else {}
if isinstance(workflow_status, str):
workflow_status = json.loads(workflow_status)

if not workflow_status:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden tool response parsing (dict/JSON/text)

Current logic assumes text then JSON.loads; handle JSON/object payloads too.

Apply:

-                workflow_status = result.content[0].text if result.content else {}
-                if isinstance(workflow_status, str):
-                    workflow_status = json.loads(workflow_status)
+                workflow_status = {}
+                if result.content:
+                    item = result.content[0]
+                    payload = getattr(item, "json", None) or getattr(item, "data", None) or getattr(item, "text", None)
+                    if isinstance(payload, str):
+                        workflow_status = json.loads(payload)
+                    elif isinstance(payload, dict):
+                        workflow_status = payload
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
workflow_status = result.content[0].text if result.content else {}
if isinstance(workflow_status, str):
workflow_status = json.loads(workflow_status)
if not workflow_status:
# Harden parsing of tool response: support raw JSON, dicts, or text
- workflow_status = result.content[0].text if result.content else {}
- if isinstance(workflow_status, str):
workflow_status = {}
if result.content:
item = result.content[0]
# Try JSON payload, then raw data, then text
payload = getattr(item, "json", None) \
or getattr(item, "data", None) \
or getattr(item, "text", None)
if isinstance(payload, str):
workflow_status = json.loads(payload)
elif isinstance(payload, dict):
workflow_status = payload
if not workflow_status:
🤖 Prompt for AI Agents
In src/mcp_agent/cli/cloud/commands/workflows/describe/main.py around lines
59–63, the code assumes the tool response is text that can be JSON.parsed;
update parsing to accept a dict/object or JSON/text: if result.content exists,
take the first content item and if it is a dict/object use it directly, if it is
a string attempt json.loads inside a try/except (catch
ValueError/JSONDecodeError) and fall back to the original string or {} as
appropriate, and ensure workflow_status is normalized to a dict (e.g., {} when
empty or when parsing fails) before the subsequent "if not workflow_status"
check.

from mcp_agent.cli.utils.ux import console
from mcp_agent.config import MCPServerSettings, Settings, LoggerSettings
from mcp_agent.mcp.gen_client import gen_client
from ...utils import setup_authenticated_client, resolve_server, handle_server_api_errors
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Blocking: resolve_server() uses run_async; calling it from async causes nested event loop errors

resolve_server() internally calls run_async; invoking it inside _signal_workflow_async (already running in an event loop) can raise “asyncio.run() cannot be called from a running event loop”. Use an async resolver.

Apply this diff to switch to an async resolver:

-from ...utils import setup_authenticated_client, resolve_server, handle_server_api_errors
+from ...utils import setup_authenticated_client, resolve_server, handle_server_api_errors
+from ...utils import resolve_server_async  # new async helper
@@
-        client = setup_authenticated_client()
-        server = resolve_server(client, server_id_or_url)
+        client = setup_authenticated_client()
+        server = await resolve_server_async(client, server_id_or_url)

Add this helper in src/mcp_agent/cli/cloud/commands/utils.py:

# utils.py
from typing import Union
from mcp_agent.cli.core.utils import run_async  # already present
from mcp_agent.app_client import MCPAppClient
from mcp_agent.app_types import MCPApp, MCPAppConfiguration  # adjust to actual types
from .utils import parse_app_identifier  # wherever it's defined

async def resolve_server_async(client: MCPAppClient, id_or_url: str) -> Union[MCPApp, MCPAppConfiguration]:
    app_id, config_id = parse_app_identifier(id_or_url)
    if config_id:
        return await client.get_app_configuration(app_config_id=config_id)
    return await client.get_app(app_id=app_id)

Also applies to: 27-36

🤖 Prompt for AI Agents
In src/mcp_agent/cli/cloud/commands/workflows/resume/main.py around line 14,
resolve_server() uses run_async and causes nested event loop errors when called
from async code; replace it with an async resolver by adding
resolve_server_async to src/mcp_agent/cli/cloud/commands/utils.py (as described
in the review) which accepts an MCPAppClient and id_or_url and awaits
client.get_app or client.get_app_configuration, then import resolve_server_async
in this file and update the calls where resolve_server is used (also at lines
~27-36) to await resolve_server_async instead of calling resolve_server,
removing any synchronous run_async wrappers.

Comment on lines +73 to +74
except Exception as e:
raise CLIError(f"Error {signal_name}ing workflow with run ID {run_id}: {str(e)}") from e
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix user-facing grammar in error messages (“resumeing”)

Map to proper gerunds.

-    except Exception as e:
-        raise CLIError(f"Error {signal_name}ing workflow with run ID {run_id}: {str(e)}") from e
+    except Exception as e:
+        gerund = {"resume": "resuming", "suspend": "suspending"}.get(signal_name, f"{signal_name}ing")
+        raise CLIError(f"Error {gerund} workflow with run ID {run_id}: {str(e)}") from e
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
except Exception as e:
raise CLIError(f"Error {signal_name}ing workflow with run ID {run_id}: {str(e)}") from e
except Exception as e:
gerund = {"resume": "resuming", "suspend": "suspending"}.get(signal_name, f"{signal_name}ing")
raise CLIError(f"Error {gerund} workflow with run ID {run_id}: {str(e)}") from e
🤖 Prompt for AI Agents
In src/mcp_agent/cli/cloud/commands/workflows/resume/main.py around lines 73-74,
the error message uses a naive string concatenation that produces incorrect
gerunds like "resumeing"; replace that with a small helper that converts the
verb in signal_name to its correct gerund form before formatting the message
(handle common rules: verbs ending in "ie" -> replace with "ying", verbs ending
in "e" -> drop the "e" and add "ing", handle short vowel-consonant by doubling
the final consonant, otherwise add "ing"), then use that gerund in the CLIError
message so it reads e.g. "resuming workflow" instead of "resumeing workflow".

@jtcorbett jtcorbett changed the base branch from main to graphite-base/424 September 8, 2025 21:06
@jtcorbett jtcorbett force-pushed the 09-05-add_workflow_commands_to_cli branch from 2a07045 to 24d3845 Compare September 8, 2025 21:06
@jtcorbett jtcorbett changed the base branch from graphite-base/424 to 09-08-temporarily_exclude_cli_from_test_coverage September 8, 2025 21:06
@jtcorbett jtcorbett changed the base branch from 09-08-temporarily_exclude_cli_from_test_coverage to graphite-base/424 September 8, 2025 21:10
@jtcorbett jtcorbett force-pushed the 09-05-add_workflow_commands_to_cli branch from 24d3845 to d0f0d96 Compare September 8, 2025 21:28
@jtcorbett jtcorbett changed the base branch from graphite-base/424 to main September 8, 2025 21:28
Copy link
Contributor Author

jtcorbett commented Sep 8, 2025

Merge activity

  • Sep 8, 9:31 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Sep 8, 9:31 PM UTC: @jtcorbett merged this pull request with Graphite.

@jtcorbett jtcorbett merged commit 7316480 into main Sep 8, 2025
6 of 7 checks passed
andrew-lastmile added a commit that referenced this pull request Sep 11, 2025
* Temporarily exclude CLI from test coverage (#429)

### TL;DR

Exclude CLI code from test coverage metrics for now. Will add tests when we're done sprinting 10000 mph 

![Added via Giphy](https://media4.giphy.com/media/v1.Y2lkPWM5NDg3NzQzOTNudmtpNXcyazNnZWo2enIzem5neXR2a3l0cGx5aWFlbDB6ZTA1dyZlcD12MV9naWZzX3NlYXJjaCZjdD1n/sRKg9r2YWeCTG5JTTo/giphy.gif)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Tests**
  * Adjusted test coverage collection to exclude non-critical CLI components, resulting in more accurate coverage metrics for core functionality.

* **Chores**
  * Updated coverage reporting configuration to align with the new exclusion rules, ensuring consistent results across local and CI runs.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

* Add workflow commands to CLI (#424)

### TL;DR

Added workflow management commands to the MCP Agent CLI, including describe, suspend, resume, and cancel operations.

### What changed?

- Added four new workflow management commands:
    - `describe_workflow`: Shows detailed information about a workflow execution
    - `suspend_workflow`: Pauses a running workflow execution
    - `resume_workflow`: Resumes a previously suspended workflow
    - `cancel_workflow`: Permanently stops a workflow execution
- Implemented corresponding API client methods in `WorkflowAPIClient`:
    - `suspend_workflow`
    - `resume_workflow`
    - `cancel_workflow`
- Updated the CLI structure to expose these commands under `mcp-agent cloud workflows`
- Added an alias for `describe_workflow` as `status` for backward compatibility

### How to test?

Test the new workflow commands with a running workflow:

```
# Get workflow details
mcp-agent cloud workflows describe run_abc123
mcp-agent cloud workflows status run_abc123  # alias

# Suspend a workflow
mcp-agent cloud workflows suspend run_abc123

# Resume a workflow (with optional payload)
mcp-agent cloud workflows resume run_abc123
mcp-agent cloud workflows resume run_abc123 --payload '{"data": "value"}'

# Cancel a workflow (with optional reason)
mcp-agent cloud workflows cancel run_abc123
mcp-agent cloud workflows cancel run_abc123 --reason "User requested cancellation"
```

### Why make this change?

These commands provide essential workflow lifecycle management capabilities to users, allowing them to monitor and control workflow executions through the CLI. The ability to suspend, resume, and cancel workflows gives users more control over long-running operations and helps manage resources more efficiently.

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- New Features
  - Introduced “workflows” CLI group with commands: describe (alias: status), resume, suspend, and cancel.
  - Describe supports text, JSON, and YAML output; all commands work with server ID or URL and include improved error messages.

- Refactor
  - Renamed CLI group from “workflow” to “workflows” and reorganized command registrations.
  - Consolidated internal utility imports (no behavior change).

- Chores
  - Updated module descriptions.
  - Removed legacy workflow status package/exports in favor of the new workflows commands.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

* add servers workflow subcommand (#428)

# Add servers workflows subcommand

This PR adds a new `workflows` subcommand to the `mcp-agent cloud servers` command that allows users to list workflows associated with a specific server. The command supports:

- Filtering by workflow status
- Limiting the number of results
- Multiple output formats (text, JSON, YAML)
- Accepting server IDs, app config IDs, or server URLs as input

Examples:
```
mcp-agent cloud servers workflows app_abc123
mcp-agent cloud servers workflows https://server.example.com --status running
mcp-agent cloud servers workflows apcnf_xyz789 --limit 10 --format json
```

The PR also cleans up the examples in the existing workflow commands and adds the necessary API client support for listing workflows.

* add workflow list and runs (#430)

### TL;DR

Reorganized workflow commands

`mcp-agent cloud workflows runs`
`mcp-agent cloud workflows list`
`mcp-agent cloud server workflows` (alias of workflows list)

### What changed?

- Moved `list_workflows_for_server` from the servers module to the workflows module as `list_workflow_runs`
- Added new workflow commands: `list_workflows` and `list_workflow_runs`
- Updated CLI command structure to make workflows commands more intuitive
- Applied consistent code formatting with black across all server and workflow related files

### How to test?

Test the new and reorganized workflow commands:

```bash
# List available workflow definitions
mcp-agent cloud workflows list app_abc123

# List workflow runs (previously under servers workflows)
mcp-agent cloud workflows runs app_abc123

# Test with different output formats
mcp-agent cloud workflows list app_abc123 --format json
mcp-agent cloud workflows runs app_abc123 --format yaml

# Verify existing commands still work
mcp-agent cloud servers list
mcp-agent cloud workflows describe app_abc123 run_xyz789
```

* [ez] Move deploy command to cloud namespace (#431)

### TL;DR

Added `cloud deploy` command as an alias for the existing `deploy` command.

* First pass at implementing the mcp-agent CLI (#409)

* Initial scaffolding

* initial CLI

* checkpoint

* checkpoint 2

* various updates to cli

* fix lint and format

* fix: should load secrets.yaml template instead when running init cli command

* fix: prevent None values in either mcp-agent secrets and config yaml files from overwriting one another when merging both

* fix: when running config check, use get_settings() instead of Settings() to ensure settings are loaded.

* fix: handle None values for servers in MCPSettings so it defaults to empty dict and update secrets.yaml template so it does not overwrite mcp servers in config

* Inform users to save and close editor to continue when running config edit command

* fix: Update openai, anthropic and azure regex for keys cli command

* Sort model list by provider and model name

* Add filtering support for models list cli command

* disable untested commands

* lint, format, gen_schema

* get rid of accidental otlp exporter changes from another branch

* get rid of accidental commit from other branch

---------

Co-authored-by: StreetLamb <[email protected]>

* Docs MVP (#436)

* Initial scaffolding

* initial CLI

* checkpoint

* checkpoint 2

* various updates to cli

* fix lint and format

* fix: should load secrets.yaml template instead when running init cli command

* fix: prevent None values in either mcp-agent secrets and config yaml files from overwriting one another when merging both

* fix: when running config check, use get_settings() instead of Settings() to ensure settings are loaded.

* fix: handle None values for servers in MCPSettings so it defaults to empty dict and update secrets.yaml template so it does not overwrite mcp servers in config

* Inform users to save and close editor to continue when running config edit command

* fix: Update openai, anthropic and azure regex for keys cli command

* Sort model list by provider and model name

* Add filtering support for models list cli command

* disable untested commands

* Fixes to docs

* Updating the main.py and !developer_secrets for secrets

* updating python entry files to main.py

* Fix tracer.py

---------

Co-authored-by: StreetLamb <[email protected]>
Co-authored-by: Andrew Hoh <[email protected]>

* fix: max complete token for openai gen structured (#438)

* Fix regression in CLI ("cloud cloud")

* docs fixes

* Fix top-level cli cloud commands (deploy, login, etc)

* Add eager tool validation to ensure json serializability of input params/result types

* More docs updates

* Refactor workflow runs list to use MCP tool calls (#439)

### TL;DR

Refactored the workflow runs listing command to use MCP tool calls instead of direct API client calls.

### What changed?

- Replaced the direct API client approach with MCP tool calls to retrieve workflow runs
- Added a new `_list_workflow_runs_async` function that uses the MCP App and gen_client to communicate with the server
- Improved status filtering and display logic to work with both object and dictionary response formats
- Enhanced error handling and formatting of workflow run information
- Updated the workflow data processing to handle different response formats more robustly

### How to test?

```bash
# List workflow runs from a server
mcp-agent cloud workflows runs <server_id_or_url>

# Filter by status
mcp-agent cloud workflows runs <server_id_or_url> --status running

# Limit results
mcp-agent cloud workflows runs <server_id_or_url> --limit 10

# Change output format
mcp-agent cloud workflows runs <server_id_or_url> --format json
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- New Features
  - Add status filtering for workflow runs, with common aliases (e.g., timeout → timed_out).
  - Add an optional limit to constrain the number of results.
  - Allow server selection via direct URL or config-based server ID.

- Refactor
  - Update text output: columns now show Workflow ID, Name, Status, Run ID, Created; Principal removed.
  - Improve date formatting and consistent JSON/YAML/Text rendering.

- Bug Fixes
  - Clearer error messages and safer handling when server info is missing or no data is returned.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

* Update workflows commands UI to be more consistant with the rest of the CLI (#432)

### TL;DR

Improved CLI workflow command output formatting with better visual indicators and consistent styling.

### How to test?

```
mcp-agent cloud workflows cancel <run-id>
mcp-agent cloud workflows describe <run-id>
mcp-agent cloud workflows resume <run-id>
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Style**
  * Cancel workflow: added a blank line before the status and changed the success icon to 🚫 (yellow).
  * Describe workflow: replaced panel UI with a clean, header-based text layout (“🔍 Workflow Details”), showing name with colorized status and fields for Workflow ID, Run ID, and Created. Updated status indicators with emojis and colors; timestamp is now plain text on its own line.
  * Resume workflow: success message now applies consistent coloring to the entire line for improved readability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

* Feature: Update Workflow Tool Calls to Work with workflow_id (#435)

* Support for workflow_id and run_id

* Update temporal workflow registry

* tests

* Update LLMS.txt

* Fix config

* Return bool for cancel result

* Validate ids provided

* Fix cancel workflow id

* Fix workflows-resume response

* Add workflow-name specific resume and cancel tools

* Fix return type

* Fix examples

* Remove redundant workflows-{name}-tool tool calls

* Add _workflow_status back

* Use registry helper

* Changes from review

* Add back evaluator_optimizer enum fix

* Fix a hang that can happen at shutdown (#440)

* Fix a shutdown hang

* Fix tests

* fix taskgroup closed in a different context than when it was started in error

* some PR feedback fixes

* PR feedback

* Fix random failures of server aggregator not found for agent in temporal (#441)

* Fix a shutdown hang

* Fix tests

* fix taskgroup closed in a different context than when it was started in error

* some PR feedback fixes

* Fix random failures of server aggregator not found for agent in temporal environment

* Bump pyproject version

* Fix gateway URL resolution (#443)

* Fix gateway URL resolution

Removed incorrect dependence on ServerRegistry for gateway URLs; the gateway is not an MCP server.
App server (src/mcp_agent/server/app_server.py) builds workflow memo with:
- gateway_url precedence: X-MCP-Gateway-URL or X-Forwarded-Url → reconstruct X-Forwarded-Proto/Host/Prefix → request.base_url → MCP_GATEWAY_URL env.
- gateway_token precedence: X-MCP-Gateway-Token → MCP_GATEWAY_TOKEN env.
Worker-side (SystemActivities/SessionProxy) uses memo.gateway_url and gateway_token; falls back to worker env.
Client proxy helpers (src/mcp_agent/mcp/client_proxy.py):
- _resolve_gateway_url: explicit param → context → env → local default.
- Updated public signatures to drop server_registry parameter.

* Cloud/deployable temporal example (#395)

* Move workflows to workflows.py file

* Fix router example

* Add remaining dependencies

* Update orchestrator to @app.async_tool example

* Changes from review

* Fix interactive_workflow to be runnable via tool

* Fix resume tool params

* Fix: Use helpful typer and invoke for root cli commands (#444)

* Use helpful typer and invoke for root cli commands

* Fix lint

* Fix enum check (#445)

* Fix/swap relative mcp agent dependency on deploy (#446)

* Update wrangler wrapper to handle requirements.txt processing

* Fix backup handling

* pass api key to workflow (#447)

* pass api key to workflow

* guard against settings not existing

---------

Co-authored-by: John Corbett <[email protected]>
Co-authored-by: Sarmad Qadri <[email protected]>
Co-authored-by: StreetLamb <[email protected]>
Co-authored-by: Yi <[email protected]>
Co-authored-by: Ryan Holinshead <[email protected]>
Co-authored-by: roman-van-der-krogt <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants