Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions src/mcp_agent/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,35 @@
}

KNOWN = {
"go",
"check",
"chat",
"dev",
"invoke",
"serve",
# Curated top-level commands
"init",
"quickstart",
"config",
"keys",
"models",
"server",
"build",
"logs",
"doctor",
"configure",
"deploy",
"login",
"whoami",
"logout",
"cloud",
# Umbrella group
"dev",
}


def main():
if len(sys.argv) > 1:
first = sys.argv[1]
if first not in KNOWN:
# Back-compat: allow `mcp-agent go ...`
if first == "go":
sys.argv.insert(1, "dev")
elif first not in KNOWN:
for i, arg in enumerate(sys.argv[1:], 1):
if arg in GO_OPTIONS or any(
arg.startswith(opt + "=") for opt in GO_OPTIONS
):
sys.argv.insert(i, "go")
# Route bare chat-like invocations to dev go (legacy behavior)
sys.argv.insert(i, "dev")
sys.argv.insert(i + 1, "go")
break
app()

Expand Down
50 changes: 34 additions & 16 deletions src/mcp_agent/cli/commands/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
attach_stdio_servers,
attach_url_servers,
load_user_app,
detect_default_script,
select_servers_from_config,
)
from mcp_agent.cli.utils.url_parser import generate_server_configs, parse_server_urls
from mcp_agent.workflows.factory import create_llm
Expand Down Expand Up @@ -99,14 +101,17 @@ def chat(
npx: Optional[str] = typer.Option(None, "--npx"),
uvx: Optional[str] = typer.Option(None, "--uvx"),
stdio: Optional[str] = typer.Option(None, "--stdio"),
script: Optional[Path] = typer.Option(Path("agent.py"), "--script"),
script: Optional[Path] = typer.Option(None, "--script"),
list_servers: bool = typer.Option(False, "--list-servers"),
list_tools: bool = typer.Option(False, "--list-tools"),
list_resources: bool = typer.Option(False, "--list-resources"),
server: Optional[str] = typer.Option(
None, "--server", help="Filter to a single server"
),
) -> None:
# Resolve script with auto-detection
script = detect_default_script(script)

server_list = servers_csv.split(",") if servers_csv else None

url_servers = None
Expand Down Expand Up @@ -140,12 +145,17 @@ def chat(
else:
server_list.extend(list(stdio_servers.keys()))

# Smart defaults for servers
resolved_server_list = select_servers_from_config(
servers_csv, url_servers, stdio_servers
)

Comment on lines +149 to +153
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Smart server defaults wired — good. One functional inconsistency remains.

/prompt still uses server_list instead of resolved_server_list, so dynamic/configured servers are ignored there.

-                                prompt_msgs = await ag.create_prompt(
+                                prompt_msgs = await ag.create_prompt(
                                     prompt_name=prompt_name,
                                     arguments=arguments,
-                                    server_names=server_list or [],
+                                    server_names=resolved_server_list or [],
                                 )
📝 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
# Smart defaults for servers
resolved_server_list = select_servers_from_config(
servers_csv, url_servers, stdio_servers
)
# Smart defaults for servers
resolved_server_list = select_servers_from_config(
servers_csv, url_servers, stdio_servers
)
prompt_msgs = await ag.create_prompt(
prompt_name=prompt_name,
arguments=arguments,
server_names=resolved_server_list or [],
)
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/chat.py around lines 149-153, the code computes
resolved_server_list but the /prompt handler still references server_list,
causing dynamic/configured servers to be ignored; update the /prompt command
handler to use resolved_server_list everywhere server_list is currently used
(pass resolved_server_list into any function calls, closures or command
construction), and add a safe fallback to resolved_server_list if server_list
may be None so the dynamic/configured server selection is honored.

💡 Verification agent

🧩 Analysis chain

Quick sweep for any other legacy server_list usages.

Run this to ensure no other call paths still rely on server_list for server_names.


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -nP --type=py -C2 '\bserver_names\s*=\s*server_list\b' || true
rg -nP --type=py -C2 '\bserver_names\s*=\s*server_list\s*\|\|\s*\[\]' || true
rg -nP --type=py -C2 'create_prompt\([^)]*server_names\s*=' || true

Length of output: 1248


Replace remaining legacy server_list usages with resolved_server_list.

rg found three call sites still passing server_list; update them to pass the resolved list (or call select_servers_from_config in that scope) and preserve or [] defaults where appropriate.

  • src/mcp_agent/cli/commands/invoke.py:65 — server_names=server_list
  • src/mcp_agent/cli/commands/go.py:113 — server_names=server_list or []
  • src/mcp_agent/cli/commands/chat.py:591 — server_names=server_list or []
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/chat.py around lines 149-153, you've already
assigned resolved_server_list from select_servers_from_config; replace the
remaining legacy server_list usages in the codebase to use that resolved list:
update src/mcp_agent/cli/commands/invoke.py at ~line 65 to pass
server_names=resolved_server_list (or call select_servers_from_config there to
obtain it), update src/mcp_agent/cli/commands/go.py at ~line 113 to pass
server_names=resolved_server_list or [], and update
src/mcp_agent/cli/commands/chat.py at ~line 591 to pass
server_names=resolved_server_list or []; preserve the existing "or []" defaults
where present.

# Listing mode (no generation)
if list_servers or list_tools or list_resources:
try:

async def _list():
app_obj = load_user_app(script or Path("agent.py"))
app_obj = load_user_app(script)
await app_obj.initialize()
attach_url_servers(app_obj, url_servers)
attach_stdio_servers(app_obj, stdio_servers)
Expand All @@ -163,7 +173,7 @@ async def _list():
agent = Agent(
name="chat-lister",
instruction="You list tools and resources",
server_names=target_servers,
server_names=resolved_server_list or target_servers,
context=app_obj.context,
)
Comment on lines +181 to 183
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Honor --server filter in Agent.server_names.

If resolved_server_list is non-empty, it currently overrides a provided --server. Prefer the explicit filter.

Apply:

-                        server_names=resolved_server_list or target_servers,
+                        server_names=([server] if server else (resolved_server_list or target_servers)),
📝 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
server_names=resolved_server_list or target_servers,
context=app_obj.context,
)
server_names=([server] if server else (resolved_server_list or target_servers)),
context=app_obj.context,
)
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/chat.py around lines 181-183, the server_names
assignment currently uses "resolved_server_list or target_servers", which lets
the resolved list override an explicit --server filter; change the logic so the
explicit target_servers (the --server filter) takes precedence by using
"target_servers or resolved_server_list" (or equivalent truthy check), ensuring
that when a --server value is provided it is honoured, falling back to
resolved_server_list only when target_servers is empty/None.

async with agent:
Expand Down Expand Up @@ -203,7 +213,7 @@ async def _list():
):

async def _parallel_repl():
app_obj = load_user_app(script or Path("agent.py"))
app_obj = load_user_app(script)
await app_obj.initialize()
attach_url_servers(app_obj, url_servers)
attach_stdio_servers(app_obj, stdio_servers)
Expand All @@ -227,7 +237,7 @@ async def _parallel_repl():
provider = prov_guess
llm = create_llm(
agent_name=m,
server_names=server_list or [],
server_names=resolved_server_list or [],
provider=(provider or "openai"),
model=m,
context=app_obj.context,
Expand Down Expand Up @@ -276,7 +286,9 @@ async def _parallel_repl():
ag = _Agent(
name="chat-lister",
instruction="list tools",
server_names=[srv] if srv else (server_list or []),
server_names=[srv]
if srv
else (resolved_server_list or []),
context=app_obj.context,
)
async with ag:
Expand All @@ -294,7 +306,9 @@ async def _parallel_repl():
ag = _Agent(
name="chat-lister",
instruction="list resources",
server_names=[srv] if srv else (server_list or []),
server_names=[srv]
if srv
else (resolved_server_list or []),
context=app_obj.context,
)
async with ag:
Expand Down Expand Up @@ -367,8 +381,8 @@ async def _gen(llm_instance):
try:
out = asyncio.run(
_run_single_model(
script=script or Path("agent.py"),
servers=server_list,
script=script,
servers=resolved_server_list,
url_servers=url_servers,
stdio_servers=stdio_servers,
model=m,
Expand All @@ -394,7 +408,7 @@ async def _gen(llm_instance):
):
# Interactive loop
async def _repl():
app_obj = load_user_app(script or Path("agent.py"))
app_obj = load_user_app(script)
await app_obj.initialize()
attach_url_servers(app_obj, url_servers)
attach_stdio_servers(app_obj, stdio_servers)
Expand All @@ -416,7 +430,7 @@ async def _repl():
provider = model_id.split(":", 1)[0]
llm = create_llm(
agent_name=(name or "chat"),
server_names=server_list or [],
server_names=resolved_server_list or [],
provider=(provider or "openai"),
model=model_id,
context=app_obj.context,
Expand Down Expand Up @@ -476,7 +490,7 @@ async def _repl():
# Recreate LLM with new model
llm_local = create_llm(
agent_name=(name or "chat"),
server_names=server_list or [],
server_names=resolved_server_list or [],
provider=(prov or "openai"),
model=model_id,
context=app_obj.context,
Expand All @@ -502,7 +516,9 @@ async def _repl():
ag = Agent(
name="chat-lister",
instruction="list tools",
server_names=[srv] if srv else (server_list or []),
server_names=[srv]
if srv
else (resolved_server_list or []),
context=app_obj.context,
)
async with ag:
Expand All @@ -521,7 +537,9 @@ async def _repl():
ag = Agent(
name="chat-lister",
instruction="list resources",
server_names=[srv] if srv else (server_list or []),
server_names=[srv]
if srv
else (resolved_server_list or []),
context=app_obj.context,
)
async with ag:
Expand Down Expand Up @@ -698,8 +716,8 @@ async def _repl():
else:
out = asyncio.run(
_run_single_model(
script=script or Path("agent.py"),
servers=server_list,
script=script,
servers=resolved_server_list,
url_servers=url_servers,
stdio_servers=stdio_servers,
model=model,
Expand Down
6 changes: 5 additions & 1 deletion src/mcp_agent/cli/commands/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
from rich.console import Console

from mcp_agent.config import get_settings
from mcp_agent.cli.core.utils import detect_default_script


app = typer.Typer(help="Run app locally with diagnostics")
console = Console()


@app.callback(invoke_without_command=True)
def dev(script: Path = typer.Option(Path("agent.py"), "--script")) -> None:
def dev(script: Path = typer.Option(None, "--script")) -> None:
"""Run the user's app script with optional live reload and preflight checks."""

def _preflight_ok() -> bool:
Expand All @@ -49,6 +50,9 @@ def _run_script() -> subprocess.Popen:
stdin=None, # Inherit stdin
)

# Resolve script path with auto-detection (main.py preferred)
script = detect_default_script(script)

# Simple preflight
_ = _preflight_ok()

Expand Down
2 changes: 1 addition & 1 deletion src/mcp_agent/cli/commands/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ def doctor() -> None:
"• Add API key: [cyan]mcp-agent keys set <provider> <key>[/cyan]\n"
"• Add server: [cyan]mcp-agent server add recipe filesystem[/cyan]\n"
"• Start chat: [cyan]mcp-agent chat --model anthropic.haiku[/cyan]\n"
"• Run agent: [cyan]mcp-agent dev --script agent.py[/cyan]",
"• Run agent: [cyan]mcp-agent dev start --script main.py[/cyan]",
title="Getting Started",
border_style="dim",
)
Expand Down
16 changes: 13 additions & 3 deletions src/mcp_agent/cli/commands/go.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
attach_stdio_servers,
attach_url_servers,
load_user_app,
detect_default_script,
select_servers_from_config,
)
from mcp_agent.cli.utils.url_parser import generate_server_configs, parse_server_urls
from mcp_agent.workflows.factory import create_llm
Expand Down Expand Up @@ -268,8 +270,11 @@ def go(
npx: Optional[str] = typer.Option(None, "--npx"),
uvx: Optional[str] = typer.Option(None, "--uvx"),
stdio: Optional[str] = typer.Option(None, "--stdio"),
script: Optional[Path] = typer.Option(Path("agent.py"), "--script"),
script: Optional[Path] = typer.Option(None, "--script"),
) -> None:
# Resolve script with auto-detection
script = detect_default_script(script)

# Parse server names from config if provided
server_list = servers.split(",") if servers else None

Expand Down Expand Up @@ -302,6 +307,11 @@ def go(
else:
server_list.extend(list(stdio_servers.keys()))

# Smart defaults from config if still unspecified
resolved_server_list = select_servers_from_config(
",".join(server_list) if server_list else None, url_servers, stdio_servers
)

# Multi-model support if comma-separated
if model and "," in model:
models = [m.strip() for m in model.split(",") if m.strip()]
Expand All @@ -311,7 +321,7 @@ def go(
asyncio.run(
_run_agent(
app_script=script,
server_list=server_list,
server_list=resolved_server_list,
model=m,
message=message,
prompt_file=prompt_file,
Expand All @@ -331,7 +341,7 @@ def go(
asyncio.run(
_run_agent(
app_script=script,
server_list=server_list,
server_list=resolved_server_list,
model=model,
message=message,
prompt_file=prompt_file,
Expand Down
58 changes: 44 additions & 14 deletions src/mcp_agent/cli/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def init(
console.print(f"Template: [cyan]{template}[/cyan] - {templates[template]}\n")

files_created = []
entry_script_name: str | None = None

# Always create config files
config_path = dir / "mcp_agent.config.yaml"
Expand All @@ -122,15 +123,35 @@ def init(

# Create template-specific files
if template == "basic":
agent_path = dir / "agent.py"
# Determine entry script name and handle existing files
script_name = "main.py"
script_path = dir / script_name
agent_content = _load_template("basic_agent.py")
if agent_content and _write(agent_path, agent_content, force):
files_created.append("agent.py")
# Make executable
try:
agent_path.chmod(agent_path.stat().st_mode | 0o111)
except Exception:
pass

if agent_content:
write_force_flag = force
if script_path.exists() and not force:
if Confirm.ask(f"{script_path} exists. Overwrite?", default=False):
write_force_flag = True
else:
# Ask for an alternate filename and ensure it ends with .py
alt_name = Prompt.ask(
"Enter a filename to save the agent", default="agent.py"
)
if not alt_name.endswith(".py"):
alt_name += ".py"
script_name = alt_name
script_path = dir / script_name
# keep write_force_flag as-is to allow overwrite prompt if needed

if _write(script_path, agent_content, write_force_flag):
files_created.append(script_name)
entry_script_name = script_name
# Make executable
try:
script_path.chmod(script_path.stat().st_mode | 0o111)
except Exception:
pass

elif template == "server":
Comment on lines +126 to 156
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Harden alt filename handling to prevent path escapes.

A user can enter an absolute path (e.g., “/tmp/x.py”) or include “../”, which would write outside the target dir. Constrain to a basename and ensure the resolved path remains within dir.

-                    alt_name = Prompt.ask(
-                        "Enter a filename to save the agent", default="agent.py"
-                    )
-                    if not alt_name.endswith(".py"):
-                        alt_name += ".py"
-                    script_name = alt_name
-                    script_path = dir / script_name
+                    alt_name = Prompt.ask(
+                        "Enter a filename to save the agent", default="agent.py"
+                    )
+                    if not alt_name.endswith(".py"):
+                        alt_name += ".py"
+                    base_dir = dir.resolve()
+                    # Keep only basename and ensure path stays within target dir
+                    script_name = Path(alt_name).name
+                    candidate_path = (base_dir / script_name).resolve()
+                    try:
+                        candidate_path.relative_to(base_dir)
+                    except ValueError:
+                        console.print("[red]Filename must be within the target directory[/red]")
+                        raise typer.Exit(1)
+                    script_path = candidate_path
+                    if script_path.exists() and script_path.is_dir():
+                        console.print(f"[red]{script_path} is a directory; choose a .py filename[/red]")
+                        raise typer.Exit(1)
📝 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
# Determine entry script name and handle existing files
script_name = "main.py"
script_path = dir / script_name
agent_content = _load_template("basic_agent.py")
if agent_content and _write(agent_path, agent_content, force):
files_created.append("agent.py")
# Make executable
try:
agent_path.chmod(agent_path.stat().st_mode | 0o111)
except Exception:
pass
if agent_content:
write_force_flag = force
if script_path.exists() and not force:
if Confirm.ask(f"{script_path} exists. Overwrite?", default=False):
write_force_flag = True
else:
# Ask for an alternate filename and ensure it ends with .py
alt_name = Prompt.ask(
"Enter a filename to save the agent", default="agent.py"
)
if not alt_name.endswith(".py"):
alt_name += ".py"
script_name = alt_name
script_path = dir / script_name
# keep write_force_flag as-is to allow overwrite prompt if needed
if _write(script_path, agent_content, write_force_flag):
files_created.append(script_name)
entry_script_name = script_name
# Make executable
try:
script_path.chmod(script_path.stat().st_mode | 0o111)
except Exception:
pass
elif template == "server":
# Determine entry script name and handle existing files
script_name = "main.py"
script_path = dir / script_name
agent_content = _load_template("basic_agent.py")
if agent_content:
write_force_flag = force
if script_path.exists() and not force:
if Confirm.ask(f"{script_path} exists. Overwrite?", default=False):
write_force_flag = True
else:
# Ask for an alternate filename and ensure it ends with .py
alt_name = Prompt.ask(
"Enter a filename to save the agent", default="agent.py"
)
if not alt_name.endswith(".py"):
alt_name += ".py"
base_dir = dir.resolve()
# Keep only basename and ensure path stays within target dir
script_name = Path(alt_name).name
candidate_path = (base_dir / script_name).resolve()
try:
candidate_path.relative_to(base_dir)
except ValueError:
console.print("[red]Filename must be within the target directory[/red]")
raise typer.Exit(1)
script_path = candidate_path
if script_path.exists() and script_path.is_dir():
console.print(f"[red]{script_path} is a directory; choose a .py filename[/red]")
raise typer.Exit(1)
# keep write_force_flag as-is to allow overwrite prompt if needed
if _write(script_path, agent_content, write_force_flag):
files_created.append(script_name)
entry_script_name = script_name
# Make executable
try:
script_path.chmod(script_path.stat().st_mode | 0o111)
except Exception:
pass
elif template == "server":
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/init.py around lines 126-156, the alternate
filename from Prompt.ask may contain absolute paths or path traversal (e.g.,
“/tmp/x.py” or “../escape.py”); sanitize this by taking only the basename (e.g.,
Path(alt_name).name), ensure it ends with “.py”, recompute script_path as dir /
sanitized_name, then verify the resolved script_path remains inside dir (e.g.,
compare dir.resolve() as a parent of script_path.resolve(), or fall back to a
safe default filename if the check fails); keep the existing write_force_flag
behavior and subsequent permission/chmod steps.

server_path = dir / "server.py"
Expand Down Expand Up @@ -185,20 +206,29 @@ def init(
console.print("2. Review and customize [cyan]mcp_agent.config.yaml[/cyan]")

if template == "basic":
console.print("3. Run your agent: [cyan]python agent.py[/cyan]")
console.print(" Or use: [cyan]mcp-agent dev --script agent.py[/cyan]")
console.print(" Or chat: [cyan]mcp-agent chat[/cyan]")
run_file = entry_script_name or "main.py"
console.print(f"3. Run your agent: [cyan]uv run {run_file}[/cyan]")
console.print(
f" Or use: [cyan]mcp-agent dev start --script {run_file}[/cyan]"
)
console.print(
f" Or serve: [cyan]mcp-agent dev serve --script {run_file}[/cyan]"
)
console.print(" Or chat: [cyan]mcp-agent dev chat[/cyan]")
console.print(
"4. Edit config: [cyan]mcp-agent config edit[/cyan] (then rerun)"
)
elif template == "server":
console.print("3. Run the server: [cyan]python server.py[/cyan]")
console.print("3. Run the server: [cyan]uv run server.py[/cyan]")
console.print(
" Or serve: [cyan]mcp-agent serve --script server.py[/cyan]"
)
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Command mismatch with CLI reorg: use mcp-agent dev serve.

Runtime commands moved under dev. This line still suggests the old top-level serve.

-            console.print(
-                "   Or serve: [cyan]mcp-agent serve --script server.py[/cyan]"
-            )
+            console.print(
+                "   Or serve: [cyan]mcp-agent dev serve --script server.py[/cyan]"
+            )

Search for other stale references:


🏁 Script executed:

#!/bin/bash
rg -nP -C1 '\bmcp-agent\s+serve\b'

Length of output: 1811


Replace remaining mcp-agent serve usages with mcp-agent dev serve

Runtime commands were moved under the dev group — update CLI help/messages and docs.

  • src/mcp_agent/cli/commands/init.py (lines ~223-225): change the printed hint to mcp-agent dev serve.
-            console.print(
-                "   Or serve: [cyan]mcp-agent serve --script server.py[/cyan]"
-            )
+            console.print(
+                "   Or serve: [cyan]mcp-agent dev serve --script server.py[/cyan]"
+            )
  • src/mcp_agent/cli/commands/serve.py (examples & output: ~lines 121-123, 471-472, 533-539): update all example and status strings to use mcp-agent dev serve (and mcp-agent dev serve test where applicable).
  • docs/cloud/agent-server.mdx (lines ~140, 145): update uv run mcp-agent serve --app ... to uv run mcp-agent dev serve --app ....
📝 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
console.print("3. Run the server: [cyan]uv run server.py[/cyan]")
console.print(
" Or serve: [cyan]mcp-agent serve --script server.py[/cyan]"
)
console.print("3. Run the server: [cyan]uv run server.py[/cyan]")
console.print(
" Or serve: [cyan]mcp-agent dev serve --script server.py[/cyan]"
)
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/init.py around lines 222 to 225, update the
printed CLI hint that currently suggests "mcp-agent serve" to the new runtime
command "mcp-agent dev serve"; replace both occurrences so the messages read "3.
Run the server: uv run server.py" and "Or serve: mcp-agent dev serve --script
server.py" (i.e., change the `mcp-agent serve` text to `mcp-agent dev serve`).

elif template == "token":
console.print("3. Run the example: [cyan]python token_example.py[/cyan]")
console.print("3. Run the example: [cyan]uv run token_example.py[/cyan]")
console.print(" Watch token usage in real-time!")
elif template == "factory":
console.print("3. Customize agents in [cyan]agents.yaml[/cyan]")
console.print("4. Run the factory: [cyan]python factory.py[/cyan]")
console.print("4. Run the factory: [cyan]uv run factory.py[/cyan]")
elif template == "minimal":
console.print("3. Create your agent script")
console.print(" See examples: [cyan]mcp-agent quickstart[/cyan]")
Expand Down
Loading
Loading