Skip to content

Commit 4f6558d

Browse files
authored
Feat/update basic quickstart template (#575)
* Update basic example * Add basic requirements.txt generation * Clarify secrets for deployment * Update README
1 parent 919ca60 commit 4f6558d

File tree

5 files changed

+123
-40
lines changed

5 files changed

+123
-40
lines changed

src/mcp_agent/cli/commands/init.py

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,34 @@ def _write_readme(dir_path: Path, content: str, force: bool) -> str | None:
7575
return None
7676

7777

78+
def _write_requirements(dir_path: Path, content: str, force: bool) -> str | None:
79+
"""Create a requirements.txt file with fallback logging if one already exists.
80+
81+
Returns the filename created, or None if it could not be written (in which case
82+
the content is printed to console as a fallback).
83+
"""
84+
path = dir_path / "requirements.txt"
85+
if not path.exists() or force:
86+
ok = _write(path, content, force)
87+
if ok:
88+
return "requirements.txt"
89+
# Fallback: print content to console if we couldn't write the file
90+
console.print(
91+
"\n[yellow]A requirements.txt already exists and could not be overwritten.[/yellow]"
92+
)
93+
console.print("[bold]Suggested requirements.txt contents:[/bold]\n")
94+
console.print(content)
95+
return None
96+
97+
7898
def _copy_pkg_tree(pkg_rel: str, dst: Path, force: bool) -> int:
7999
"""Copy packaged examples from mcp_agent.data/examples/<pkg_rel> into dst.
80100
81101
Uses importlib.resources to locate files installed with the package.
82102
Returns 1 on success, 0 on failure.
83103
"""
84104
try:
85-
root = (
86-
resources.files("mcp_agent.data")
87-
.joinpath("examples")
88-
.joinpath(pkg_rel)
89-
)
105+
root = resources.files("mcp_agent.data").joinpath("examples").joinpath(pkg_rel)
90106
except Exception:
91107
return 0
92108
if not root.exists():
@@ -116,7 +132,9 @@ def init(
116132
ctx: typer.Context,
117133
dir: Path = typer.Option(Path("."), "--dir", "-d", help="Target directory"),
118134
template: str = typer.Option("basic", "--template", "-t", help="Template to use"),
119-
quickstart: str = typer.Option(None, "--quickstart", help="Quickstart mode: copy example without config files"),
135+
quickstart: str = typer.Option(
136+
None, "--quickstart", help="Quickstart mode: copy example without config files"
137+
),
120138
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing files"),
121139
no_gitignore: bool = typer.Option(
122140
False, "--no-gitignore", help="Skip creating .gitignore"
@@ -172,7 +190,10 @@ def init(
172190
"mcp-basic-agent": ("mcp_basic_agent", "basic/mcp_basic_agent"),
173191
"token-counter": ("token_counter", "basic/token_counter"),
174192
"agent-factory": ("agent_factory", "basic/agent_factory"),
175-
"reference-agent-server": ("reference_agent_server", "mcp_agent_server/reference"),
193+
"reference-agent-server": (
194+
"reference_agent_server",
195+
"mcp_agent_server/reference",
196+
),
176197
"elicitation": ("elicitation", "mcp_agent_server/elicitation"),
177198
"sampling": ("sampling", "mcp_agent_server/sampling"),
178199
"notifications": ("notifications", "mcp_agent_server/notifications"),
@@ -187,7 +208,9 @@ def init(
187208

188209
# Templates table
189210
console.print("[bold cyan]Templates:[/bold cyan]")
190-
console.print("[dim]Creates minimal project structure with config files[/dim]\n")
211+
console.print(
212+
"[dim]Creates minimal project structure with config files[/dim]\n"
213+
)
191214
table1 = Table(show_header=True, header_style="cyan")
192215
table1.add_column("Template", style="green")
193216
table1.add_column("Description")
@@ -233,7 +256,9 @@ def init(
233256
if copied:
234257
console.print(f"Copied {copied} set(s) to {dst}")
235258
else:
236-
console.print(f"[yellow]Could not copy '{quickstart}' - destination may already exist[/yellow]")
259+
console.print(
260+
f"[yellow]Could not copy '{quickstart}' - destination may already exist[/yellow]"
261+
)
237262
console.print("Use --force to overwrite")
238263

239264
return
@@ -285,15 +310,19 @@ def init(
285310
copied = _copy_pkg_tree(pkg_rel, dst, force)
286311

287312
if copied:
288-
console.print(f"\n[green]✅ Successfully copied example '{template}'![/green]")
313+
console.print(
314+
f"\n[green]✅ Successfully copied example '{template}'![/green]"
315+
)
289316
console.print(f"Created: [cyan]{dst}[/cyan]\n")
290317
console.print("[bold]Next steps:[/bold]")
291318
console.print(f"1. cd [cyan]{dst}[/cyan]")
292319
console.print("2. Review the README for instructions")
293320
console.print("3. Add your API keys to config/secrets files if needed")
294321
else:
295322
console.print(f"[yellow]Example '{template}' could not be copied[/yellow]")
296-
console.print("The destination may already exist. Use --force to overwrite.")
323+
console.print(
324+
"The destination may already exist. Use --force to overwrite."
325+
)
297326

298327
return
299328

@@ -337,6 +366,13 @@ def init(
337366
if created:
338367
files_created.append(created)
339368

369+
# Add basic requirements.txt
370+
requirements_content = _load_template("requirements.txt")
371+
if requirements_content:
372+
created = _write_requirements(dir, requirements_content, force)
373+
if created:
374+
files_created.append(created)
375+
340376
elif template == "server":
341377
server_path = dir / "server.py"
342378
server_content = _load_template("basic_agent_server.py")

src/mcp_agent/data/templates/README_init.md

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ Welcome! This project was generated by `mcp-agent init`. It’s a minimal, reada
1515

1616
## Quick start
1717

18-
1. Add API keys to `mcp_agent.secrets.yaml` (or set env vars):
18+
1. Add your OpenAI API key to `mcp_agent.secrets.yaml` (or set `OPENAI_API_KEY` env var).
1919

20-
- `OPENAI_API_KEY` (recommended)
21-
- `ANTHROPIC_API_KEY` (optional)
20+
NOTE: You can use another supported provider (e.g. Anthropic) instead, just be sure to set its API key in the `mcp_agent.secrets.yaml` (or set its env var) and import/use the relevant `AugmentedLLM` in `main.py`.
2221

2322
2. Review `mcp_agent.config.yaml`:
2423

@@ -30,6 +29,7 @@ Welcome! This project was generated by `mcp-agent init`. It’s a minimal, reada
3029
3. Run locally:
3130

3231
```bash
32+
uv pip install -r requirements.txt
3333
uv run main.py
3434
```
3535

@@ -38,23 +38,58 @@ You’ll see two summaries printed:
3838
- A summary of `README.md` from your current directory.
3939
- A summary of the intro page at modelcontextprotocol.io.
4040

41-
4. Deploy a remote MCP server:
42-
43-
### Run as an MCP server
41+
4. Run locally as an MCP server:
4442

4543
- In `main.py`, UNCOMMENT the server lines that call `create_mcp_server_for_app(agent_app)` and `run_sse_async()`.
4644
- Start the server: `uv run main.py`
45+
- Once you see the server started, e.g.
46+
```bash
47+
Uvicorn running on http://127.0.0.1:8000
48+
```
49+
you can connect to it with your preferred MCP Client. For example, you can use [MCP Inspector](https://github.com/modelcontextprotocol/inspector) to explore and test the server:
50+
51+
```bash
52+
npx @modelcontextprotocol/inspector --transport sse --server-url http://127.0.0.1:8000/sse
53+
```
54+
55+
5. Deploy as a remote MCP server:
56+
57+
When you're ready to deploy, ensure the required API keys are set in `mcp_agent.secrets.yaml` and then run:
58+
59+
```bash
60+
uv run mcp-agent login
61+
```
62+
63+
to authenticate to mcp-agent cloud. You will be redirected to the login page, create an mcp-agent cloud account through Google or Github.
4764

48-
When you're ready to deploy, simply run:
65+
Set up your mcp-agent cloud API Key and copy & paste it into your terminal
4966

5067
```bash
51-
mcp-agent deploy "hello_world"
68+
INFO: Directing to MCP Agent Cloud API login...
69+
Please enter your API key 🔑:
5270
```
5371

54-
- This wraps your app as a hosted MCP SSE server.
55-
- Anything decorated with `@app.tool` (or `@app.async_tool`) runs as a Temporal workflow in the cloud.
72+
In your terminal, deploy the MCP app:
73+
74+
```bash
75+
uv run mcp-agent deploy hello_world
76+
```
77+
78+
You will then be prompted to specify the type of secret to save your OpenAI API key as. Select (1) deployment secret so that it is available to the deployed server.
79+
80+
The `deploy` command will bundle the app files and deploy them, wrapping your app as a hosted MCP SSE server with a URL of the form:
81+
`https://<server_id>.deployments.mcp-agent.com`.
82+
83+
Anything decorated with `@app.tool` (or `@app.async_tool`) runs as a Temporal workflow in the cloud.
84+
85+
Since the mcp-agent app is exposed as an MCP server, it can be used in any MCP client just
86+
like any other MCP server. For example, you can inspect and test the server using MCP Inspector:
87+
88+
```bash
89+
npx @modelcontextprotocol/inspector --transport sse --server-url https://<server_id>.deployments.mcp-agent.com/sse
90+
```
5691

57-
Notes
92+
## Notes
5893

5994
- `app_ctx` is the MCPApp Context (configuration, logger, upstream session, etc.).
6095
- Logging uses `app.logger` and is forwarded as notifications when connected to an MCP client.

src/mcp_agent/data/templates/basic_agent.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
- @app.tool and @app.async_tool decorators to expose your agents as long-running tools on an MCP server.
88
- Advanced MCP features: Notifications, sampling, and elicitation
99
10-
You can run this example locally using "uv run main.py", and also deploy it as an MCP server using "mcp-agent deploy".
10+
You can run this example locally using "uv run main.py", and also deploy it as an MCP server using "uv run mcp-agent deploy".
1111
1212
Let's get started!
1313
"""
@@ -21,7 +21,12 @@
2121
from mcp_agent.agents.agent import Agent
2222
from mcp_agent.agents.agent_spec import AgentSpec
2323
from mcp_agent.core.context import Context as AppContext
24+
25+
# UNCOMMENT to run this MCPApp as a server
26+
# from mcp_agent.server.app_server import create_mcp_server_for_app
2427
from mcp_agent.workflows.factory import create_agent
28+
29+
# We are using the OpenAI augmented LLM for this example but you can swap with others (e.g. AnthropicAugmentedLLM)
2530
from mcp_agent.workflows.llm.augmented_llm_openai import OpenAIAugmentedLLM
2631

2732
# Create the MCPApp, the root of mcp-agent.
@@ -134,7 +139,8 @@ async def main():
134139
print("Webpage summary:")
135140
print(webpage_summary)
136141

137-
# UNCOMMENT to run this MCPApp as an MCP server
142+
# UNCOMMENT to run this MCPApp as an MCP server (also uncomment the import of create_mcp_server_for_app at the top)
143+
# NOTE: You can comment-out the above agent runs if you only want to run the server
138144
#########################################################
139145
# Create the MCP server that exposes both workflows and agent configurations,
140146
# optionally using custom FastMCP settings
@@ -148,7 +154,7 @@ async def main():
148154
asyncio.run(main())
149155

150156
# When you're ready to deploy this MCPApp as a remote SSE server, run:
151-
# > mcp-agent deploy "hello_world"
157+
# > uv run mcp-agent deploy "hello_world"
152158
#
153159
# Congrats! You made it to the end of the getting-started example!
154160
# There is a lot more that mcp-agent can do, and we hope you'll explore the rest of the documentation.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mcp-agent
2+
3+
# Optionally, include additional dependencies required for this project
4+
openai
5+
# anthropic

src/mcp_agent/data/templates/secrets.yaml

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,27 @@
22
# WARNING: Keep this file secure and never commit to version control
33

44
# Provider API Keys
5+
# We default to OpenAI, but you can configure your preferred providers here.
56
# You can also set these as environment variables instead
67
openai:
7-
api_key: "" # Or use OPENAI_API_KEY env var
8+
api_key: "" # Or remove and use OPENAI_API_KEY env var
89

9-
anthropic:
10-
api_key: "" # Or use ANTHROPIC_API_KEY env var
10+
# anthropic:
11+
# api_key: "" # Or remove and use ANTHROPIC_API_KEY env var
1112

12-
google:
13-
api_key: "" # Or use GOOGLE_API_KEY env var
13+
# google:
14+
# api_key: "" # Or remove and use GOOGLE_API_KEY env var
1415

15-
azure:
16-
api_key: "" # Or use AZURE_API_KEY env var
17-
base_url: "" # https://your-resource.openai.azure.com/
18-
api_version: "2024-02-01"
19-
# use_default_azure_credential: false # Set to true for DefaultAzureCredential
16+
# azure:
17+
# api_key: "" # Or remove and use AZURE_API_KEY env var
18+
# base_url: "" # https://your-resource.openai.azure.com/
19+
# api_version: "2024-02-01"
20+
# # use_default_azure_credential: false # Set to true for DefaultAzureCredential
2021

21-
bedrock:
22-
aws_access_key_id: "" # Or use AWS_ACCESS_KEY_ID env var
23-
aws_secret_access_key: "" # Or use AWS_SECRET_ACCESS_KEY env var
24-
aws_region: "us-east-1"
22+
# bedrock:
23+
# aws_access_key_id: "" # Or remove and use AWS_ACCESS_KEY_ID env var
24+
# aws_secret_access_key: "" # Or remove and use AWS_SECRET_ACCESS_KEY env var
25+
# aws_region: "us-east-1"
2526

2627
# MCP Server environment variables
2728
# mcp:
@@ -31,4 +32,4 @@ bedrock:
3132
# GITHUB_PERSONAL_ACCESS_TOKEN: ghp_...
3233
# brave-search:
3334
# env:
34-
# BRAVE_API_KEY: BSA_...
35+
# BRAVE_API_KEY: BSA_...

0 commit comments

Comments
 (0)