Skip to content

Conversation

@jtcorbett
Copy link
Contributor

@jtcorbett jtcorbett commented Oct 22, 2025

TL;DR

Unified project initialization by merging init and quickstart commands into a single enhanced init command with improved template management.

What changed?

  • Consolidated mcp-agent quickstart functionality into mcp-agent init with a new --quickstart flag for backward compatibility
  • Organized templates into two categories: scaffolding templates and example templates
  • Added --list option to display all available templates with descriptions
  • Enhanced CLI options with short forms (-d, -t, -f, -l)
  • Added new option --no-gitignore to skip creating .gitignore files
  • Improved documentation with clearer examples and template descriptions
  • Removed the standalone quickstart.py module as its functionality is now in init.py
  • Updated CLI reference documentation to reflect these changes

How to test?

# List all available templates
mcp-agent init --list

# Create scaffolding project with config files
mcp-agent init --template basic

# Copy complete example with config files
mcp-agent init --template workflow --dir ./my-project

# Use quickstart mode (backward compatible with old command)
mcp-agent init --quickstart workflow

Summary by CodeRabbit

  • New Features
    • Added --quickstart option to the init command for copying curated example templates alongside project scaffolding.
    • Example templates now available during project initialization.
  • Chores
    • Consolidated quickstart functionality into the init command; separate quickstart command group removed.
    • Updated init help text to reflect dual-mode scaffolding capabilities.

Copy link
Contributor Author

jtcorbett commented Oct 22, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@jtcorbett jtcorbett changed the base branch from main to graphite-base/569 October 22, 2025 20:59
@jtcorbett jtcorbett force-pushed the 10-22-merge_init_and_quickstart branch from 253263e to 1fe7425 Compare October 22, 2025 20:59
@jtcorbett jtcorbett changed the base branch from graphite-base/569 to 10-22-bump_uv October 22, 2025 20:59
@coderabbitai
Copy link

coderabbitai bot commented Oct 22, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The PR consolidates the standalone quickstart CLI command into the init command. The quickstart.py module is deleted, its functionality (copying example templates via helper functions) is migrated to init.py with a new --quickstart option, and CLI exports and mounting are updated accordingly.

Changes

Cohort / File(s) Change Summary
Quickstart Module Removal
src/mcp_agent/cli/commands/__init__.py, src/mcp_agent/cli/commands/quickstart.py
Removed quickstart from module exports and deleted entire quickstart.py file containing standalone Typer CLI with 13 subcommands for copying example template sets
Init Command Enhancement
src/mcp_agent/cli/commands/init.py
Added --quickstart option, introduced _copy_tree() and _copy_pkg_tree() helper functions for copying examples from filesystem or packaged resources, split templates into scaffolding_templates and example_templates categories, enhanced interactive flow to wire quickstart mode
CLI Main Updates
src/mcp_agent/cli/main.py
Removed quickstart import and top-level CLI mounting, updated init command help text to reflect dual-mode functionality: "Scaffold a new mcp-agent project or copy curated examples"

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

The changes involve heterogeneous modifications across CLI structure and initialization logic. The primary complexity stems from the migration of file-copying logic and example handling into init.py, including resource packaging interactions via importlib. While the refactoring is cohesive and follows a clear consolidation pattern, verifying correct integration of example copying, error handling, and interactive mode wiring requires careful attention.

Possibly related PRs

Suggested reviewers

  • saqadri
  • rholinshead

Poem

🐰 The quickstart command takes a leap,
Into init's burrow, nestled deep,
With copy helpers hopping bright,
Templates split—left and right,
One unified command, sleek and neat! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "merge init and quickstart" is fully related to the main change in this pull request. The changeset consolidates the standalone quickstart CLI module into the init command, removing quickstart.py entirely and integrating its functionality into init.py via a new --quickstart flag and helper functions. The title is concise, clear, and directly captures the primary objective without vague terms, emojis, or unnecessary noise.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 10-22-merge_init_and_quickstart

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 Oct 22, 2025
@jtcorbett jtcorbett force-pushed the 10-22-merge_init_and_quickstart branch from 1fe7425 to a2c38bc Compare October 22, 2025 21:14
@jtcorbett jtcorbett changed the base branch from 10-22-bump_uv to graphite-base/569 October 22, 2025 21:15
@jtcorbett jtcorbett marked this pull request as ready for review October 22, 2025 21:15
@jtcorbett jtcorbett force-pushed the 10-22-merge_init_and_quickstart branch from a2c38bc to 4a71c20 Compare October 22, 2025 21:15
@graphite-app graphite-app bot changed the base branch from graphite-base/569 to main October 22, 2025 21:15
@jtcorbett jtcorbett force-pushed the 10-22-merge_init_and_quickstart branch from 4a71c20 to 160ccb8 Compare October 22, 2025 21:15
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: 2

Caution

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

⚠️ Outside diff range comments (2)
docs/cli-reference.mdx (2)

218-223: Align aliases with CLI: only ‘deploy’ and ‘login’ are top-level.

Docs list logout and whoami as top-level aliases, but main.py registers only deploy and login. Adjust docs or add aliases in code.

-These commands are available at the top level for convenience:
-- `mcp-agent deploy` - Deploy to cloud (alias for `cloud deploy`)
-- `mcp-agent login` - Authenticate (alias for `cloud auth login`)
-- `mcp-agent logout` - Sign out (alias for `cloud auth logout`)
-- `mcp-agent whoami` - Show current identity (alias for `cloud auth whoami`)
+These commands are available at the top level for convenience:
+- `mcp-agent deploy` - Deploy to cloud (alias for `cloud deploy`)
+- `mcp-agent login` - Authenticate (alias for `cloud auth login`)
+
+Other auth helpers are available under `mcp-agent cloud auth`.

442-457: Replace non-existent template ‘temporal’ with a valid one.

temporal isn’t in scaffolding_templates. Use server (or basic) in examples.

-# Initialize project
-mcp-agent init --template temporal
+# Initialize project
+mcp-agent init --template server
@@
-# Create examples
-mcp-agent init --quickstart workflow
+# Create examples
+mcp-agent init --quickstart workflow
🧹 Nitpick comments (3)
src/mcp_agent/cli/commands/init.py (2)

222-235: Deduplicate example_map and favor packaged resources first.

example_map is defined twice; this will drift. Move a single EXAMPLES_MAP constant to module scope and reuse in both quickstart and template flows. Also prefer _copy_pkg_tree first for all entries, then fall back to EXAMPLE_ROOT when developing from repo.

@@
-        example_map = {
-            "workflow": (EXAMPLE_ROOT / "workflows", "workflow"),
-            "researcher": (EXAMPLE_ROOT / "usecases" / "mcp_researcher", "researcher"),
-            "data-analysis": (EXAMPLE_ROOT / "usecases" / "mcp_financial_analyzer", "data-analysis"),
-            "state-transfer": (EXAMPLE_ROOT / "workflows" / "workflow_router", "state-transfer"),
-            "basic-agent-server": (EXAMPLE_ROOT / "mcp_agent_server" / "asyncio", "basic_agent_server"),
-            "mcp-basic-agent": (None, "mcp_basic_agent", "basic/mcp_basic_agent"),
-            "token-counter": (None, "token_counter", "basic/token_counter"),
-            "agent-factory": (None, "agent_factory", "basic/agent_factory"),
-            "reference-agent-server": (None, "reference_agent_server", "mcp_agent_server/reference"),
-            "elicitation": (None, "elicitation", "mcp_agent_server/elicitation"),
-            "sampling": (None, "sampling", "mcp_agent_server/sampling"),
-            "notifications": (None, "notifications", "mcp_agent_server/notifications"),
-        }
+# At top-level (near EXAMPLE_ROOT)
+EXAMPLES_MAP = {
+    # pkg_rel preferred (packaged), repo_rel fallback for dev
+    "workflow": {"dst": "workflow", "pkg_rel": "workflows", "repo_rel": ["workflows"]},
+    "researcher": {"dst": "researcher", "pkg_rel": "usecases/mcp_researcher", "repo_rel": ["usecases", "mcp_researcher"]},
+    "data-analysis": {"dst": "data-analysis", "pkg_rel": "usecases/mcp_financial_analyzer", "repo_rel": ["usecases", "mcp_financial_analyzer"]},
+    "state-transfer": {"dst": "state-transfer", "pkg_rel": "workflows/workflow_router", "repo_rel": ["workflows", "workflow_router"]},
+    "basic-agent-server": {"dst": "basic_agent_server", "pkg_rel": "mcp_agent_server/asyncio", "repo_rel": ["mcp_agent_server", "asyncio"]},
+    "mcp-basic-agent": {"dst": "mcp_basic_agent", "pkg_rel": "basic/mcp_basic_agent"},
+    "token-counter": {"dst": "token_counter", "pkg_rel": "basic/token_counter"},
+    "agent-factory": {"dst": "agent_factory", "pkg_rel": "basic/agent_factory"},
+    "reference-agent-server": {"dst": "reference_agent_server", "pkg_rel": "mcp_agent_server/reference"},
+    "elicitation": {"dst": "elicitation", "pkg_rel": "mcp_agent_server/elicitation"},
+    "sampling": {"dst": "sampling", "pkg_rel": "mcp_agent_server/sampling"},
+    "notifications": {"dst": "notifications", "pkg_rel": "mcp_agent_server/notifications"},
+}
@@
-        mapping = example_map.get(quickstart)
+        mapping = EXAMPLES_MAP.get(quickstart)
@@
-        if len(mapping) == 3:
-            _, dst_name, pkg_rel = mapping
-            dst = base_dir / dst_name
-            copied = _copy_pkg_tree(pkg_rel, dst, force)
-            if not copied:
-                src = EXAMPLE_ROOT / pkg_rel.replace("/", "_")
-                if src.exists():
-                    copied = _copy_tree(src, dst, force)
-        else:
-            src, dst_name = mapping
-            dst = base_dir / dst_name
-            copied = _copy_tree(src, dst, force)
+        info = mapping
+        dst = base_dir / info["dst"]
+        copied = 0
+        if "pkg_rel" in info:
+            copied = _copy_pkg_tree(info["pkg_rel"], dst, force)
+        if not copied and "repo_rel" in info:
+            repo_src = EXAMPLE_ROOT.joinpath(*info["repo_rel"])
+            if repo_src.exists():
+                copied = _copy_tree(repo_src, dst, force)
@@
-        example_map = { ... }  # duplicate removed
-        mapping = example_map.get(template)
+        mapping = EXAMPLES_MAP.get(template)
@@
-        if len(mapping) == 3:
-            _, dst_name, pkg_rel = mapping
-            dst = dir / dst_name
-            copied = _copy_pkg_tree(pkg_rel, dst, force)
-            if not copied:
-                src = EXAMPLE_ROOT / pkg_rel.replace("/", "_")
-                if src.exists():
-                    copied = _copy_tree(src, dst, force)
-        else:
-            src, dst_name = mapping
-            dst = dir / dst_name
-            copied = _copy_tree(src, dst, force)
+        info = mapping
+        dst = dir / info["dst"]
+        copied = 0
+        if "pkg_rel" in info:
+            copied = _copy_pkg_tree(info["pkg_rel"], dst, force)
+        if not copied and "repo_rel" in info:
+            repo_src = EXAMPLE_ROOT.joinpath(*info["repo_rel"])
+            if repo_src.exists():
+                copied = _copy_tree(repo_src, dst, force)

Also applies to: 306-319


91-97: Avoid destructive rmtree; improve failure messaging.

  • Using rmtree on dst is heavy-handed; prefer shutil.copytree(..., dirs_exist_ok=force) (Python 3.8+).
  • Quickstart failure message blames destination only; also surface source-not-found.
@@
-        if dst.exists():
-            if force:
-                shutil.rmtree(dst)
-            else:
-                return 0
-        shutil.copytree(src, dst)
+        # Copy allowing overwrite when force=True
+        shutil.copytree(src, dst, dirs_exist_ok=force)
         return 1
@@
-        else:
-            console.print(f"[yellow]Could not copy '{quickstart}' - destination may already exist[/yellow]")
-            console.print("Use --force to overwrite")
+        else:
+            console.print(f"[yellow]Could not copy '{quickstart}'[/yellow]")
+            console.print("Possible causes: destination exists without --force, or example not found in package/repo.")
+            console.print("Use --list to see names and --force to overwrite.")

Also applies to: 258-263

docs/cli-reference.mdx (1)

49-55: Docs sync with code: options and template categories look good; keep them in lockstep.

Minor wording nit: “copy example only without config files” → “copy example without config files” (remove ‘only’ for consistency with CLI help).

-| `--quickstart` | Quickstart mode: copy example only without config files | - |
+| `--quickstart` | Quickstart mode: copy example without config files | - |

Also applies to: 56-79, 80-97

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 739380f and 160ccb8.

📒 Files selected for processing (5)
  • docs/cli-reference.mdx (2 hunks)
  • src/mcp_agent/cli/commands/__init__.py (0 hunks)
  • src/mcp_agent/cli/commands/init.py (6 hunks)
  • src/mcp_agent/cli/commands/quickstart.py (0 hunks)
  • src/mcp_agent/cli/main.py (1 hunks)
💤 Files with no reviewable changes (2)
  • src/mcp_agent/cli/commands/init.py
  • src/mcp_agent/cli/commands/quickstart.py
🔇 Additional comments (1)
src/mcp_agent/cli/main.py (1)

146-146: LGTM: init help reflects merged quickstart.

console = Console()

# Path to repository examples
EXAMPLE_ROOT = Path(__file__).parents[4] / "examples"
Copy link
Member

Choose a reason for hiding this comment

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

Can we use absolute path here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was taken from the old quickstart implementation. Not sure how we can have an absolute path from the repo root?

Copy link
Collaborator

Choose a reason for hiding this comment

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

No, this won't work. The quickstart samples need to ship with the package. i.e. look at how init materializes the basic agent from the data directory and use that logic.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, ok. This was confusing because we have the init command which uses the src/data/examples and src/data/templates to generate init projects from the mcp-agent src. This here is copying from the repo itself so it won't work if you run it in your own project folder. But looks like this is how quickstart currently does it (I just tried it in a new project dir and it fails for each of them).

So is the change needed here just to duplicate those examples under src/data/examples or try and fetch the examples from the repo?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just duplicated them under data/examples in a followup PR

@jtcorbett jtcorbett force-pushed the 10-22-merge_init_and_quickstart branch from 160ccb8 to 20288a3 Compare October 23, 2025 13:42
@jtcorbett jtcorbett force-pushed the 10-22-merge_init_and_quickstart branch from 20288a3 to b52015f Compare October 23, 2025 13:48
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: 6

♻️ Duplicate comments (2)
src/mcp_agent/cli/commands/init.py (2)

17-20: Good fix: stderr handling with a dedicated Rich console.

Defining err_console and using it for error output resolves the previous TypeError from Console.print(err=True).


556-565: Don’t manually construct Typer.Context; get the current one.

Manual Context() construction is brittle. Use typer.get_current_context(), and you don’t need to pass quickstart explicitly.

Apply:

-    ctx = typer.Context(init)
-    init(
-        ctx=ctx,
+    ctx = typer.get_current_context()
+    init(
+        ctx=ctx,
         dir=dir,
         template=template_name,
-        quickstart=None,
         force=False,
         no_gitignore=False,
         list_templates=False,
     )
🧹 Nitpick comments (3)
src/mcp_agent/cli/commands/init.py (3)

216-222: Harden quickstart guard and route errors to stderr.

Be explicit about type and print errors via err_console.

Apply:

-    if quickstart:
-        if quickstart not in example_templates:
-            console.print(f"[red]Unknown quickstart example: {quickstart}[/red]")
-            console.print(f"Available examples: {', '.join(example_templates.keys())}")
-            console.print("[dim]Use --list to see all available templates[/dim]")
+    if isinstance(quickstart, str) and quickstart:
+        if quickstart not in example_templates:
+            err_console.print(f"[red]Unknown quickstart example: {quickstart}[/red]")
+            err_console.print(f"Available examples: {', '.join(example_templates.keys())}")
+            err_console.print("[dim]Use --list to see all available templates[/dim]")
             raise typer.Exit(1)

35-51: Send error logs to stderr console consistently.

Use err_console for failures in _load_template and _write for consistent UX and easier piping.

Apply:

-    except Exception as e:
-        console.print(f"[red]Error loading template {template_name}: {e}[/red]")
+    except Exception as e:
+        err_console.print(f"[red]Error loading template {template_name}: {e}[/red]")
         return ""
@@
-    except Exception as e:
-        console.print(f"[red]Error writing {path}: {e}[/red]")
+    except Exception as e:
+        err_console.print(f"[red]Error writing {path}: {e}[/red]")
         return False

210-211: Improve help text to include quickstart usage.

Clarify that examples can be copied via --quickstart.

Apply:

-        console.print("\n[dim]Use: mcp-agent init --template <name>[/dim]")
+        console.print("\n[dim]Use: mcp-agent init --template <name>  or  mcp-agent init --quickstart <name>[/dim]")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 160ccb8 and b52015f.

📒 Files selected for processing (4)
  • src/mcp_agent/cli/commands/__init__.py (0 hunks)
  • src/mcp_agent/cli/commands/init.py (7 hunks)
  • src/mcp_agent/cli/commands/quickstart.py (0 hunks)
  • src/mcp_agent/cli/main.py (1 hunks)
💤 Files with no reviewable changes (2)
  • src/mcp_agent/cli/commands/init.py
  • src/mcp_agent/cli/commands/quickstart.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/mcp_agent/cli/main.py

Comment on lines +110 to +121
try:
root = (
_pkg_files("mcp_agent")
.joinpath("data")
.joinpath("examples")
.joinpath(pkg_rel)
)
except Exception:
return 0
if not root.exists():
return 0

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: importlib.resources Traversable has no .exists(); use .is_dir() and handle existing dst.

Calling root.exists() on a Traversable will raise AttributeError at runtime. Also, mirror _copy_tree semantics when dst exists.

Apply:

 def _copy_pkg_tree(pkg_rel: str, dst: Path, force: bool) -> int:
@@
-    try:
-        root = (
-            _pkg_files("mcp_agent")
-            .joinpath("data")
-            .joinpath("examples")
-            .joinpath(pkg_rel)
-        )
-    except Exception:
-        return 0
-    if not root.exists():
-        return 0
+    try:
+        root = (
+            _pkg_files("mcp_agent")
+            .joinpath("data")
+            .joinpath("examples")
+            .joinpath(pkg_rel)
+        )
+    except Exception:
+        return 0
+    # Traversable doesn't define `.exists()`; use `.is_dir()`
+    if not root.is_dir():
+        return 0
+
+    # Align behavior with _copy_tree when destination already exists
+    if dst.exists():
+        if force:
+            shutil.rmtree(dst)
+        else:
+            return 0
📝 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
try:
root = (
_pkg_files("mcp_agent")
.joinpath("data")
.joinpath("examples")
.joinpath(pkg_rel)
)
except Exception:
return 0
if not root.exists():
return 0
try:
root = (
_pkg_files("mcp_agent")
.joinpath("data")
.joinpath("examples")
.joinpath(pkg_rel)
)
except Exception:
return 0
# Traversable doesn't define `.exists()`; use `.is_dir()`
if not root.is_dir():
return 0
# Align behavior with _copy_tree when destination already exists
if dst.exists():
if force:
shutil.rmtree(dst)
else:
return 0
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/init.py around lines 110 to 121, the code calls
root.exists() on an importlib.resources Traversable which raises AttributeError;
replace that check with root.is_dir() (or root.is_file() as appropriate) and
ensure you treat a non-directory as absent; additionally, when copying the tree
to the destination, mirror the semantics of _copy_tree by handling an existing
dst (e.g., merge files, skip existing files, or overwrite according to the
project's policy) rather than unconditionally failing—update the copy logic to
check for dst existence and perform the merge/skip/overwrite behavior used by
_copy_tree.

Comment on lines +170 to +184
example_templates = {
"workflow": "Workflow examples (from examples/workflows)",
"researcher": "MCP researcher use case (from examples/usecases/mcp_researcher)",
"data-analysis": "Financial data analysis example",
"state-transfer": "Workflow router with state transfer",
"mcp-basic-agent": "Basic MCP agent example",
"token-counter": "Token counting with monitoring",
"agent-factory": "Agent factory pattern",
"basic-agent-server": "Basic agent server (asyncio)",
"reference-agent-server": "Reference agent server implementation",
"elicitation": "Elicitation server example",
"sampling": "Sampling server example",
"notifications": "Notifications server example",
}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unlisted quickstarts: examples present in mapping but not shown with --list.

hello-world, mcp, temporal, chatgpt-app are selectable via mapping but omitted from example_templates. Add them so users can discover them.

Apply:

     example_templates = {
         "workflow": "Workflow examples (from examples/workflows)",
         "researcher": "MCP researcher use case (from examples/usecases/mcp_researcher)",
         "data-analysis": "Financial data analysis example",
         "state-transfer": "Workflow router with state transfer",
         "mcp-basic-agent": "Basic MCP agent example",
         "token-counter": "Token counting with monitoring",
         "agent-factory": "Agent factory pattern",
         "basic-agent-server": "Basic agent server (asyncio)",
         "reference-agent-server": "Reference agent server implementation",
         "elicitation": "Elicitation server example",
         "sampling": "Sampling server example",
         "notifications": "Notifications server example",
+        "hello-world": "Cloud hello world example",
+        "mcp": "Cloud MCP example",
+        "temporal": "Cloud Temporal example",
+        "chatgpt-app": "Cloud ChatGPT app example",
     }
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/init.py around lines 170 to 184, the
example_templates mapping is missing entries for quickstarts that exist
elsewhere (hello-world, mcp, temporal, chatgpt-app); update the
example_templates dict to include those four keys with descriptive values (e.g.,
"Hello World quickstart", "MCP quickstart", "Temporal quickstart", "ChatGPT app
quickstart") so they appear when users run --list.

Comment on lines +223 to +240
example_map = {
"workflow": (EXAMPLE_ROOT / "workflows", "workflow"),
"researcher": (EXAMPLE_ROOT / "usecases" / "mcp_researcher", "researcher"),
"data-analysis": (EXAMPLE_ROOT / "usecases" / "mcp_financial_analyzer", "data-analysis"),
"state-transfer": (EXAMPLE_ROOT / "workflows" / "workflow_router", "state-transfer"),
"basic-agent-server": (EXAMPLE_ROOT / "mcp_agent_server" / "asyncio", "basic_agent_server"),
"mcp-basic-agent": (None, "mcp_basic_agent", "basic/mcp_basic_agent"),
"token-counter": (None, "token_counter", "basic/token_counter"),
"agent-factory": (None, "agent_factory", "basic/agent_factory"),
"reference-agent-server": (None, "reference_agent_server", "mcp_agent_server/reference"),
"elicitation": (None, "elicitation", "mcp_agent_server/elicitation"),
"sampling": (None, "sampling", "mcp_agent_server/sampling"),
"notifications": (None, "notifications", "mcp_agent_server/notifications"),
"hello-world": (EXAMPLE_ROOT / "cloud" / "hello_world", "hello_world"),
"mcp": (EXAMPLE_ROOT / "cloud" / "mcp", "mcp"),
"temporal": (EXAMPLE_ROOT / "cloud" / "temporal", "temporal"),
"chatgpt-app": (EXAMPLE_ROOT / "cloud" / "chatgpt_app", "chatgpt_app"),
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Repo path reliance breaks in installed wheels; use packaged examples for all entries.

Several quickstarts only reference EXAMPLE_ROOT; those won’t exist when the package is installed. Prefer packaged resources first, then fall back to repo paths in dev.

Apply:

-        example_map = {
-            "workflow": (EXAMPLE_ROOT / "workflows", "workflow"),
-            "researcher": (EXAMPLE_ROOT / "usecases" / "mcp_researcher", "researcher"),
-            "data-analysis": (EXAMPLE_ROOT / "usecases" / "mcp_financial_analyzer", "data-analysis"),
-            "state-transfer": (EXAMPLE_ROOT / "workflows" / "workflow_router", "state-transfer"),
-            "basic-agent-server": (EXAMPLE_ROOT / "mcp_agent_server" / "asyncio", "basic_agent_server"),
-            "mcp-basic-agent": (None, "mcp_basic_agent", "basic/mcp_basic_agent"),
-            "token-counter": (None, "token_counter", "basic/token_counter"),
-            "agent-factory": (None, "agent_factory", "basic/agent_factory"),
-            "reference-agent-server": (None, "reference_agent_server", "mcp_agent_server/reference"),
-            "elicitation": (None, "elicitation", "mcp_agent_server/elicitation"),
-            "sampling": (None, "sampling", "mcp_agent_server/sampling"),
-            "notifications": (None, "notifications", "mcp_agent_server/notifications"),
-            "hello-world": (EXAMPLE_ROOT / "cloud" / "hello_world", "hello_world"),
-            "mcp": (EXAMPLE_ROOT / "cloud" / "mcp", "mcp"),
-            "temporal": (EXAMPLE_ROOT / "cloud" / "temporal", "temporal"),
-            "chatgpt-app": (EXAMPLE_ROOT / "cloud" / "chatgpt_app", "chatgpt_app"),
-        }
+        example_map = {
+            # Prefer packaged examples; repo fallback happens below if needed
+            "workflow": (None, "workflow", "workflows"),
+            "researcher": (None, "researcher", "usecases/mcp_researcher"),
+            "data-analysis": (None, "data-analysis", "usecases/mcp_financial_analyzer"),
+            "state-transfer": (None, "state-transfer", "workflows/workflow_router"),
+            "basic-agent-server": (None, "basic_agent_server", "mcp_agent_server/asyncio"),
+            "mcp-basic-agent": (None, "mcp_basic_agent", "basic/mcp_basic_agent"),
+            "token-counter": (None, "token_counter", "basic/token_counter"),
+            "agent-factory": (None, "agent_factory", "basic/agent_factory"),
+            "reference-agent-server": (None, "reference_agent_server", "mcp_agent_server/reference"),
+            "elicitation": (None, "elicitation", "mcp_agent_server/elicitation"),
+            "sampling": (None, "sampling", "mcp_agent_server/sampling"),
+            "notifications": (None, "notifications", "mcp_agent_server/notifications"),
+            "hello-world": (None, "hello_world", "cloud/hello_world"),
+            "mcp": (None, "mcp", "cloud/mcp"),
+            "temporal": (None, "temporal", "cloud/temporal"),
+            "chatgpt-app": (None, "chatgpt_app", "cloud/chatgpt_app"),
+        }

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

Comment on lines +250 to +258
if len(mapping) == 3:
_, dst_name, pkg_rel = mapping
dst = base_dir / dst_name
copied = _copy_pkg_tree(pkg_rel, dst, force)
if not copied:
src = EXAMPLE_ROOT / pkg_rel.replace("/", "_")
if src.exists():
copied = _copy_tree(src, dst, force)
else:
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fallback to repo path uses an incorrect join.

pkg_rel.replace("/", "_") won’t match the repo layout; join the original segments under EXAMPLE_ROOT.

Apply:

-            if not copied:
-                src = EXAMPLE_ROOT / pkg_rel.replace("/", "_")
+            if not copied:
+                # Dev fallback: repo examples mirror the packaged relative path
+                src = EXAMPLE_ROOT / Path(pkg_rel)
                 if src.exists():
                     copied = _copy_tree(src, dst, force)
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/init.py around lines 250 to 258, the fallback
constructs src with EXAMPLE_ROOT / pkg_rel.replace("/", "_") which produces the
wrong path; split pkg_rel on "/" and join the segments under EXAMPLE_ROOT (e.g.
EXAMPLE_ROOT.joinpath(*pkg_rel.split("/")) or EXAMPLE_ROOT /
Path(*pkg_rel.split("/"))) so the repo layout is preserved, then check
src.exists() and use _copy_tree(src, dst, force) as before.

Comment on lines +306 to +328
# Handle example templates (copy from repository or package)
if template in example_templates:
# Map template names to their source paths
# Format: "name": (repo_path, dest_name) for repo examples
# "name": (None, dest_name, pkg_rel) for packaged examples
example_map = {
"workflow": (EXAMPLE_ROOT / "workflows", "workflow"),
"researcher": (EXAMPLE_ROOT / "usecases" / "mcp_researcher", "researcher"),
"data-analysis": (EXAMPLE_ROOT / "usecases" / "mcp_financial_analyzer", "data-analysis"),
"state-transfer": (EXAMPLE_ROOT / "workflows" / "workflow_router", "state-transfer"),
"basic-agent-server": (EXAMPLE_ROOT / "mcp_agent_server" / "asyncio", "basic_agent_server"),
"mcp-basic-agent": (None, "mcp_basic_agent", "basic/mcp_basic_agent"),
"token-counter": (None, "token_counter", "basic/token_counter"),
"agent-factory": (None, "agent_factory", "basic/agent_factory"),
"reference-agent-server": (None, "reference_agent_server", "mcp_agent_server/reference"),
"elicitation": (None, "elicitation", "mcp_agent_server/elicitation"),
"sampling": (None, "sampling", "mcp_agent_server/sampling"),
"notifications": (None, "notifications", "mcp_agent_server/notifications"),
"hello-world": (EXAMPLE_ROOT / "cloud" / "hello_world", "hello_world"),
"mcp": (EXAMPLE_ROOT / "cloud" / "mcp", "mcp"),
"temporal": (EXAMPLE_ROOT / "cloud" / "temporal", "temporal"),
"chatgpt-app": (EXAMPLE_ROOT / "cloud" / "chatgpt_app", "chatgpt_app"),
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Same packaging issue for --template flow; mirror the quickstart fix.

The template example_map also relies on EXAMPLE_ROOT for many entries. Use packaged paths with repo fallback.

Apply:

-        example_map = {
-            "workflow": (EXAMPLE_ROOT / "workflows", "workflow"),
-            "researcher": (EXAMPLE_ROOT / "usecases" / "mcp_researcher", "researcher"),
-            "data-analysis": (EXAMPLE_ROOT / "usecases" / "mcp_financial_analyzer", "data-analysis"),
-            "state-transfer": (EXAMPLE_ROOT / "workflows" / "workflow_router", "state-transfer"),
-            "basic-agent-server": (EXAMPLE_ROOT / "mcp_agent_server" / "asyncio", "basic_agent_server"),
-            "mcp-basic-agent": (None, "mcp_basic_agent", "basic/mcp_basic_agent"),
-            "token-counter": (None, "token_counter", "basic/token_counter"),
-            "agent-factory": (None, "agent_factory", "basic/agent_factory"),
-            "reference-agent-server": (None, "reference_agent_server", "mcp_agent_server/reference"),
-            "elicitation": (None, "elicitation", "mcp_agent_server/elicitation"),
-            "sampling": (None, "sampling", "mcp_agent_server/sampling"),
-            "notifications": (None, "notifications", "mcp_agent_server/notifications"),
-            "hello-world": (EXAMPLE_ROOT / "cloud" / "hello_world", "hello_world"),
-            "mcp": (EXAMPLE_ROOT / "cloud" / "mcp", "mcp"),
-            "temporal": (EXAMPLE_ROOT / "cloud" / "temporal", "temporal"),
-            "chatgpt-app": (EXAMPLE_ROOT / "cloud" / "chatgpt_app", "chatgpt_app"),
-        }
+        example_map = {
+            "workflow": (None, "workflow", "workflows"),
+            "researcher": (None, "researcher", "usecases/mcp_researcher"),
+            "data-analysis": (None, "data-analysis", "usecases/mcp_financial_analyzer"),
+            "state-transfer": (None, "state-transfer", "workflows/workflow_router"),
+            "basic-agent-server": (None, "basic_agent_server", "mcp_agent_server/asyncio"),
+            "mcp-basic-agent": (None, "mcp_basic_agent", "basic/mcp_basic_agent"),
+            "token-counter": (None, "token_counter", "basic/token_counter"),
+            "agent-factory": (None, "agent_factory", "basic/agent_factory"),
+            "reference-agent-server": (None, "reference_agent_server", "mcp_agent_server/reference"),
+            "elicitation": (None, "elicitation", "mcp_agent_server/elicitation"),
+            "sampling": (None, "sampling", "mcp_agent_server/sampling"),
+            "notifications": (None, "notifications", "mcp_agent_server/notifications"),
+            "hello-world": (None, "hello_world", "cloud/hello_world"),
+            "mcp": (None, "mcp", "cloud/mcp"),
+            "temporal": (None, "temporal", "cloud/temporal"),
+            "chatgpt-app": (None, "chatgpt_app", "cloud/chatgpt_app"),
+        }
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/init.py around lines 306 to 328, the example_map
currently hardcodes many entries to EXAMPLE_ROOT rather than using packaged
resource paths with a repository fallback (same bug fixed for quickstart);
update the mapping so entries prefer packaged paths (i.e., use tuples of the
form (None, dest_name, pkg_rel) for packaged examples) and for repo-only
examples keep the EXAMPLE_ROOT tuples, then adjust the code that resolves
examples to first try loading from the package path and only fall back to
EXAMPLE_ROOT if the packaged resource is not present, ensuring parity with the
quickstart fix approach.

Comment on lines +340 to +343
src = EXAMPLE_ROOT / pkg_rel.replace("/", "_")
if src.exists():
copied = _copy_tree(src, dst, force)
else:
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Same incorrect fallback join as quickstart.

Use EXAMPLE_ROOT / Path(pkg_rel), not underscore replacement.

Apply:

-            if not copied:
-                src = EXAMPLE_ROOT / pkg_rel.replace("/", "_")
+            if not copied:
+                src = EXAMPLE_ROOT / Path(pkg_rel)
                 if src.exists():
                     copied = _copy_tree(src, dst, force)
🤖 Prompt for AI Agents
In src/mcp_agent/cli/commands/init.py around lines 340 to 343, the code
incorrectly builds the example path using pkg_rel.replace("/", "_"); change it
to use a Path join such as EXAMPLE_ROOT / Path(pkg_rel) so the directory
structure is preserved. Replace the underscore-replacement expression with
Path(pkg_rel) (ensure pathlib.Path is imported or already available), keep the
existing exists() check and _copy_tree call, and remove the replace("/") usage.

Copy link
Contributor Author

jtcorbett commented Oct 23, 2025

Merge activity

  • Oct 23, 2:38 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Oct 23, 2:38 PM UTC: @jtcorbett merged this pull request with Graphite.

@jtcorbett jtcorbett merged commit bd97817 into main Oct 23, 2025
8 checks passed
andrew-lastmile pushed a commit to andrew-lastmile/mcp-agent-fork that referenced this pull request Nov 4, 2025
### TL;DR

Unified project initialization by merging `init` and `quickstart` commands into a single enhanced `init` command with improved template management.

### What changed?

- Consolidated `mcp-agent quickstart` functionality into `mcp-agent init` with a new `--quickstart` flag for backward compatibility
- Organized templates into two categories: scaffolding templates and example templates
- Added `--list` option to display all available templates with descriptions
- Enhanced CLI options with short forms (`-d`, `-t`, `-f`, `-l`)
- Added new option `--no-gitignore` to skip creating .gitignore files
- Improved documentation with clearer examples and template descriptions
- Removed the standalone `quickstart.py` module as its functionality is now in `init.py`
- Updated CLI reference documentation to reflect these changes

### How to test?

```bash
# List all available templates
mcp-agent init --list

# Create scaffolding project with config files
mcp-agent init --template basic

# Copy complete example with config files
mcp-agent init --template workflow --dir ./my-project

# Use quickstart mode (backward compatible with old command)
mcp-agent init --quickstart workflow
```

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

## Summary by CodeRabbit

- **New Features**
    - Added `--quickstart` option to the init command for copying curated example templates alongside project scaffolding.
    - Example templates now available during project initialization.
- **Chores**
    - Consolidated quickstart functionality into the init command; separate quickstart command group removed.
    - Updated init help text to reflect dual-mode scaffolding capabilities.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

4 participants