fast-agent-mcp 0.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fast-agent-mcp might be problematic. Click here for more details.
- fast_agent_mcp-0.0.7.dist-info/METADATA +322 -0
- fast_agent_mcp-0.0.7.dist-info/RECORD +100 -0
- fast_agent_mcp-0.0.7.dist-info/WHEEL +4 -0
- fast_agent_mcp-0.0.7.dist-info/entry_points.txt +5 -0
- fast_agent_mcp-0.0.7.dist-info/licenses/LICENSE +201 -0
- mcp_agent/__init__.py +0 -0
- mcp_agent/agents/__init__.py +0 -0
- mcp_agent/agents/agent.py +277 -0
- mcp_agent/app.py +303 -0
- mcp_agent/cli/__init__.py +0 -0
- mcp_agent/cli/__main__.py +4 -0
- mcp_agent/cli/commands/bootstrap.py +221 -0
- mcp_agent/cli/commands/config.py +11 -0
- mcp_agent/cli/commands/setup.py +229 -0
- mcp_agent/cli/main.py +68 -0
- mcp_agent/cli/terminal.py +24 -0
- mcp_agent/config.py +334 -0
- mcp_agent/console.py +28 -0
- mcp_agent/context.py +251 -0
- mcp_agent/context_dependent.py +48 -0
- mcp_agent/core/fastagent.py +1013 -0
- mcp_agent/eval/__init__.py +0 -0
- mcp_agent/event_progress.py +88 -0
- mcp_agent/executor/__init__.py +0 -0
- mcp_agent/executor/decorator_registry.py +120 -0
- mcp_agent/executor/executor.py +293 -0
- mcp_agent/executor/task_registry.py +34 -0
- mcp_agent/executor/temporal.py +405 -0
- mcp_agent/executor/workflow.py +197 -0
- mcp_agent/executor/workflow_signal.py +325 -0
- mcp_agent/human_input/__init__.py +0 -0
- mcp_agent/human_input/handler.py +49 -0
- mcp_agent/human_input/types.py +58 -0
- mcp_agent/logging/__init__.py +0 -0
- mcp_agent/logging/events.py +123 -0
- mcp_agent/logging/json_serializer.py +163 -0
- mcp_agent/logging/listeners.py +216 -0
- mcp_agent/logging/logger.py +365 -0
- mcp_agent/logging/rich_progress.py +120 -0
- mcp_agent/logging/tracing.py +140 -0
- mcp_agent/logging/transport.py +461 -0
- mcp_agent/mcp/__init__.py +0 -0
- mcp_agent/mcp/gen_client.py +85 -0
- mcp_agent/mcp/mcp_activity.py +18 -0
- mcp_agent/mcp/mcp_agent_client_session.py +242 -0
- mcp_agent/mcp/mcp_agent_server.py +56 -0
- mcp_agent/mcp/mcp_aggregator.py +394 -0
- mcp_agent/mcp/mcp_connection_manager.py +330 -0
- mcp_agent/mcp/stdio.py +104 -0
- mcp_agent/mcp_server_registry.py +275 -0
- mcp_agent/progress_display.py +10 -0
- mcp_agent/resources/examples/decorator/main.py +26 -0
- mcp_agent/resources/examples/decorator/optimizer.py +78 -0
- mcp_agent/resources/examples/decorator/orchestrator.py +68 -0
- mcp_agent/resources/examples/decorator/parallel.py +81 -0
- mcp_agent/resources/examples/decorator/router.py +56 -0
- mcp_agent/resources/examples/decorator/tiny.py +22 -0
- mcp_agent/resources/examples/mcp_researcher/main-evalopt.py +53 -0
- mcp_agent/resources/examples/mcp_researcher/main.py +38 -0
- mcp_agent/telemetry/__init__.py +0 -0
- mcp_agent/telemetry/usage_tracking.py +18 -0
- mcp_agent/workflows/__init__.py +0 -0
- mcp_agent/workflows/embedding/__init__.py +0 -0
- mcp_agent/workflows/embedding/embedding_base.py +61 -0
- mcp_agent/workflows/embedding/embedding_cohere.py +49 -0
- mcp_agent/workflows/embedding/embedding_openai.py +46 -0
- mcp_agent/workflows/evaluator_optimizer/__init__.py +0 -0
- mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +359 -0
- mcp_agent/workflows/intent_classifier/__init__.py +0 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_base.py +120 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +134 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +45 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +45 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +161 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +60 -0
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +60 -0
- mcp_agent/workflows/llm/__init__.py +0 -0
- mcp_agent/workflows/llm/augmented_llm.py +645 -0
- mcp_agent/workflows/llm/augmented_llm_anthropic.py +539 -0
- mcp_agent/workflows/llm/augmented_llm_openai.py +615 -0
- mcp_agent/workflows/llm/llm_selector.py +345 -0
- mcp_agent/workflows/llm/model_factory.py +175 -0
- mcp_agent/workflows/orchestrator/__init__.py +0 -0
- mcp_agent/workflows/orchestrator/orchestrator.py +407 -0
- mcp_agent/workflows/orchestrator/orchestrator_models.py +154 -0
- mcp_agent/workflows/orchestrator/orchestrator_prompts.py +113 -0
- mcp_agent/workflows/parallel/__init__.py +0 -0
- mcp_agent/workflows/parallel/fan_in.py +350 -0
- mcp_agent/workflows/parallel/fan_out.py +187 -0
- mcp_agent/workflows/parallel/parallel_llm.py +141 -0
- mcp_agent/workflows/router/__init__.py +0 -0
- mcp_agent/workflows/router/router_base.py +276 -0
- mcp_agent/workflows/router/router_embedding.py +240 -0
- mcp_agent/workflows/router/router_embedding_cohere.py +59 -0
- mcp_agent/workflows/router/router_embedding_openai.py +59 -0
- mcp_agent/workflows/router/router_llm.py +301 -0
- mcp_agent/workflows/swarm/__init__.py +0 -0
- mcp_agent/workflows/swarm/swarm.py +320 -0
- mcp_agent/workflows/swarm/swarm_anthropic.py +42 -0
- mcp_agent/workflows/swarm/swarm_openai.py +41 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""Bootstrap command to create example applications."""
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
from rich.panel import Panel
|
|
9
|
+
|
|
10
|
+
app = typer.Typer(
|
|
11
|
+
help="Create example applications and learn MCP Agent patterns",
|
|
12
|
+
no_args_is_help=True,
|
|
13
|
+
)
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
EXAMPLE_TYPES = {
|
|
17
|
+
"decorator": {
|
|
18
|
+
"description": "Decorator pattern example showing different agent composition approaches",
|
|
19
|
+
"details": """
|
|
20
|
+
The decorator example shows how to:
|
|
21
|
+
- Compose agents using the decorator pattern
|
|
22
|
+
- Add capabilities like optimization and routing
|
|
23
|
+
- Run agents in parallel
|
|
24
|
+
- Handle complex agent interactions
|
|
25
|
+
""",
|
|
26
|
+
"files": [
|
|
27
|
+
"main.py",
|
|
28
|
+
"optimizer.py",
|
|
29
|
+
"orchestrator.py",
|
|
30
|
+
"parallel.py",
|
|
31
|
+
"router.py",
|
|
32
|
+
"tiny.py",
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
"researcher": {
|
|
36
|
+
"description": "Research agent example with evaluation optimization",
|
|
37
|
+
"details": """
|
|
38
|
+
The researcher example demonstrates:
|
|
39
|
+
- Building a research-focused agent
|
|
40
|
+
- Implementing evaluation strategies
|
|
41
|
+
- Optimizing agent responses
|
|
42
|
+
- Handling complex research tasks
|
|
43
|
+
""",
|
|
44
|
+
"files": ["main.py", "main-evalopt.py"],
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def copy_example_files(
|
|
50
|
+
example_type: str, target_dir: Path, force: bool = False
|
|
51
|
+
) -> list[str]:
|
|
52
|
+
"""Copy example files from resources to target directory."""
|
|
53
|
+
created = []
|
|
54
|
+
|
|
55
|
+
# During development, use the source directory
|
|
56
|
+
source_dir = (
|
|
57
|
+
Path(__file__).parent.parent.parent
|
|
58
|
+
/ "resources"
|
|
59
|
+
/ "examples"
|
|
60
|
+
/ ("decorator" if example_type == "decorator" else "mcp_researcher")
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
if not source_dir.exists():
|
|
64
|
+
console.print(f"[red]Error: Source directory not found: {source_dir}[/red]")
|
|
65
|
+
return created
|
|
66
|
+
|
|
67
|
+
for filename in EXAMPLE_TYPES[example_type]["files"]:
|
|
68
|
+
source = source_dir / filename
|
|
69
|
+
target = target_dir / filename
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
if not source.exists():
|
|
73
|
+
console.print(f"[red]Error: Source file not found: {source}[/red]")
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
if target.exists() and not force:
|
|
77
|
+
console.print(f"[yellow]Skipping[/yellow] {filename} (already exists)")
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
shutil.copy2(source, target)
|
|
81
|
+
created.append(filename)
|
|
82
|
+
console.print(f"[green]Created[/green] {filename}")
|
|
83
|
+
|
|
84
|
+
except Exception as e:
|
|
85
|
+
console.print(f"[red]Error copying {filename}: {str(e)}[/red]")
|
|
86
|
+
|
|
87
|
+
return created
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def show_examples_overview():
|
|
91
|
+
"""Show an overview of available examples."""
|
|
92
|
+
console.print("\n[bold]MCP Agent Example Applications[/bold]")
|
|
93
|
+
console.print("Learn how to build effective agents through practical examples\n")
|
|
94
|
+
|
|
95
|
+
# Create a table for the examples
|
|
96
|
+
table = Table(title="Available Examples")
|
|
97
|
+
table.add_column("Example", style="green")
|
|
98
|
+
table.add_column("Description")
|
|
99
|
+
table.add_column("Files", style="blue")
|
|
100
|
+
|
|
101
|
+
for name, info in EXAMPLE_TYPES.items():
|
|
102
|
+
table.add_row(name, info["description"], "\n".join(info["files"]))
|
|
103
|
+
|
|
104
|
+
console.print(table)
|
|
105
|
+
|
|
106
|
+
# Show usage instructions
|
|
107
|
+
console.print("\n[bold]Usage:[/bold]")
|
|
108
|
+
console.print("1. Create a new example:")
|
|
109
|
+
console.print(" mcp-agent bootstrap create <example-name>")
|
|
110
|
+
console.print("\n2. Specify a directory:")
|
|
111
|
+
console.print(
|
|
112
|
+
" mcp-agent bootstrap create <example-name> --directory ./my-project"
|
|
113
|
+
)
|
|
114
|
+
console.print("\n3. Force overwrite existing files:")
|
|
115
|
+
console.print(" mcp-agent bootstrap create <example-name> --force")
|
|
116
|
+
|
|
117
|
+
console.print("\n[bold]Examples:[/bold]")
|
|
118
|
+
console.print(" mcp-agent bootstrap create decorator")
|
|
119
|
+
console.print(
|
|
120
|
+
" mcp-agent bootstrap create researcher --directory ./research-agent"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@app.callback(invoke_without_command=True)
|
|
125
|
+
def main(ctx: typer.Context):
|
|
126
|
+
"""Bootstrap example applications to learn MCP Agent patterns.
|
|
127
|
+
|
|
128
|
+
Create working examples that demonstrate different agent patterns and capabilities.
|
|
129
|
+
Use these as starting points for your own agent applications.
|
|
130
|
+
"""
|
|
131
|
+
if ctx.invoked_subcommand is None:
|
|
132
|
+
show_examples_overview()
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@app.command()
|
|
136
|
+
def create(
|
|
137
|
+
example_type: str = typer.Argument(
|
|
138
|
+
None, help="Type of example to create (decorator or researcher)"
|
|
139
|
+
),
|
|
140
|
+
directory: str = typer.Option(
|
|
141
|
+
".", "--directory", "-d", help="Directory where example files will be created"
|
|
142
|
+
),
|
|
143
|
+
force: bool = typer.Option(
|
|
144
|
+
False, "--force", "-f", help="Force overwrite existing files"
|
|
145
|
+
),
|
|
146
|
+
):
|
|
147
|
+
"""Create a new example application.
|
|
148
|
+
|
|
149
|
+
This will create a set of example files based on the chosen type:
|
|
150
|
+
|
|
151
|
+
\b
|
|
152
|
+
- decorator: Decorator pattern example showing different agent composition approaches
|
|
153
|
+
- researcher: Research agent example with evaluation optimization
|
|
154
|
+
"""
|
|
155
|
+
if not example_type:
|
|
156
|
+
show_examples_overview()
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
example_type = example_type.lower()
|
|
160
|
+
if example_type not in EXAMPLE_TYPES:
|
|
161
|
+
console.print(f"[red]Error:[/red] Unknown example type '{example_type}'")
|
|
162
|
+
console.print("\nAvailable types:")
|
|
163
|
+
for name in EXAMPLE_TYPES:
|
|
164
|
+
console.print(f" - {name}")
|
|
165
|
+
raise typer.Exit(1)
|
|
166
|
+
|
|
167
|
+
target_dir = Path(directory).resolve()
|
|
168
|
+
if not target_dir.exists():
|
|
169
|
+
target_dir.mkdir(parents=True)
|
|
170
|
+
console.print(f"Created directory: {target_dir}")
|
|
171
|
+
|
|
172
|
+
# Show example details
|
|
173
|
+
console.print(f"\n[bold]Creating {example_type} example[/bold]")
|
|
174
|
+
console.print(
|
|
175
|
+
Panel(
|
|
176
|
+
EXAMPLE_TYPES[example_type]["details"].strip(),
|
|
177
|
+
title="About this example",
|
|
178
|
+
expand=False,
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
if not force:
|
|
183
|
+
# Check for existing files first
|
|
184
|
+
existing = []
|
|
185
|
+
for f in EXAMPLE_TYPES[example_type]["files"]:
|
|
186
|
+
if (target_dir / f).exists():
|
|
187
|
+
existing.append(f)
|
|
188
|
+
|
|
189
|
+
if existing:
|
|
190
|
+
console.print(
|
|
191
|
+
"\n[yellow]Warning:[/yellow] The following files already exist:"
|
|
192
|
+
)
|
|
193
|
+
for f in existing:
|
|
194
|
+
console.print(f" - {f}")
|
|
195
|
+
console.print("\nUse --force to overwrite existing files")
|
|
196
|
+
raise typer.Exit(1)
|
|
197
|
+
|
|
198
|
+
created = copy_example_files(example_type, target_dir, force)
|
|
199
|
+
|
|
200
|
+
if created:
|
|
201
|
+
console.print("\n[green]Setup completed successfully![/green]")
|
|
202
|
+
console.print("\nCreated files:")
|
|
203
|
+
for f in created:
|
|
204
|
+
console.print(f" - {f}")
|
|
205
|
+
|
|
206
|
+
console.print("\n[bold]Next Steps:[/bold]")
|
|
207
|
+
if example_type == "decorator":
|
|
208
|
+
console.print("1. Review main.py for the basic example")
|
|
209
|
+
console.print("2. Check other files for different composition patterns:")
|
|
210
|
+
console.print(" - optimizer.py: Add optimization capabilities")
|
|
211
|
+
console.print(" - router.py: Route requests to different agents")
|
|
212
|
+
console.print(" - parallel.py: Run agents in parallel")
|
|
213
|
+
console.print("3. Run with: python main.py")
|
|
214
|
+
else:
|
|
215
|
+
console.print("1. Review main.py for the basic researcher example")
|
|
216
|
+
console.print(
|
|
217
|
+
"2. Try main-evalopt.py for the evaluation optimization version"
|
|
218
|
+
)
|
|
219
|
+
console.print("3. Run with: python main.py or python main-evalopt.py")
|
|
220
|
+
else:
|
|
221
|
+
console.print("\n[yellow]No files were created.[/yellow]")
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import typer
|
|
3
|
+
from rich.prompt import Confirm
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
|
|
6
|
+
app = typer.Typer()
|
|
7
|
+
console = Console()
|
|
8
|
+
|
|
9
|
+
FASTAGENT_CONFIG_TEMPLATE = """
|
|
10
|
+
# FastAgent Configuration File
|
|
11
|
+
|
|
12
|
+
# Default Model Configuration:
|
|
13
|
+
#
|
|
14
|
+
# Takes format:
|
|
15
|
+
# <provider>.<model_string>.<reasoning_effort?> (e.g. anthropic.claude-3-5-sonnet-20241022 or openai.o3-mini.low)
|
|
16
|
+
# Accepts aliases for Anthropic Models: haiku, haiku3, sonnet, sonnet35, opus, opus3
|
|
17
|
+
# and OpenAI Models: gpt-4o-mini, gpt-4o, o1, o1-mini, o3-mini
|
|
18
|
+
#
|
|
19
|
+
# If not specified, defaults to "haiku".
|
|
20
|
+
# Can be overriden with a command line switch --model=<model>, or within the Agent constructor.
|
|
21
|
+
|
|
22
|
+
default_model: sonnet
|
|
23
|
+
|
|
24
|
+
# Logging and Console Configuration:
|
|
25
|
+
logging:
|
|
26
|
+
# level: "debug" | "info" | "warning" | "error"
|
|
27
|
+
# type: "none" | "console" | "file" | "http"
|
|
28
|
+
# path: "/path/to/logfile.jsonl"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Switch the progress display on or off
|
|
32
|
+
# progress_display: true
|
|
33
|
+
|
|
34
|
+
# Show chat User/Assistant messages on the console
|
|
35
|
+
# show_chat: true
|
|
36
|
+
# Show tool calls on the console
|
|
37
|
+
# show_tools: true
|
|
38
|
+
# Truncate long tool responses on the console
|
|
39
|
+
# truncate_tools: true
|
|
40
|
+
|
|
41
|
+
# MCP Servers
|
|
42
|
+
mcp:
|
|
43
|
+
servers:
|
|
44
|
+
fetch:
|
|
45
|
+
command: "uvx"
|
|
46
|
+
args: ["mcp-server-fetch"]
|
|
47
|
+
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
FASTAGENT_SECRETS_TEMPLATE = """
|
|
51
|
+
# FastAgent Secrets Configuration
|
|
52
|
+
# WARNING: Keep this file secure and never commit to version control
|
|
53
|
+
|
|
54
|
+
openai:
|
|
55
|
+
api_key: <your-api-key-here>
|
|
56
|
+
anthropic:
|
|
57
|
+
api_key: <your-api-key-here>
|
|
58
|
+
|
|
59
|
+
# Example of setting an MCP Server environment variable
|
|
60
|
+
mcp:
|
|
61
|
+
servers:
|
|
62
|
+
brave:
|
|
63
|
+
env:
|
|
64
|
+
BRAVE_API_KEY: <your_api_key_here>
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
GITIGNORE_TEMPLATE = """
|
|
69
|
+
# FastAgent secrets file
|
|
70
|
+
fastagent-secrets.yaml
|
|
71
|
+
|
|
72
|
+
# Python
|
|
73
|
+
__pycache__/
|
|
74
|
+
*.py[cod]
|
|
75
|
+
*$py.class
|
|
76
|
+
*.so
|
|
77
|
+
.Python
|
|
78
|
+
build/
|
|
79
|
+
develop-eggs/
|
|
80
|
+
dist/
|
|
81
|
+
downloads/
|
|
82
|
+
eggs/
|
|
83
|
+
.eggs/
|
|
84
|
+
lib/
|
|
85
|
+
lib64/
|
|
86
|
+
parts/
|
|
87
|
+
sdist/
|
|
88
|
+
var/
|
|
89
|
+
wheels/
|
|
90
|
+
*.egg-info/
|
|
91
|
+
.installed.cfg
|
|
92
|
+
*.egg
|
|
93
|
+
|
|
94
|
+
# Virtual Environment
|
|
95
|
+
.env
|
|
96
|
+
.venv
|
|
97
|
+
env/
|
|
98
|
+
venv/
|
|
99
|
+
ENV/
|
|
100
|
+
|
|
101
|
+
# IDE
|
|
102
|
+
.idea/
|
|
103
|
+
.vscode/
|
|
104
|
+
*.swp
|
|
105
|
+
*.swo
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
AGENT_EXAMPLE_TEMPLATE = """
|
|
109
|
+
import asyncio
|
|
110
|
+
from mcp_agent.core.fastagent import FastAgent
|
|
111
|
+
|
|
112
|
+
# Create the application
|
|
113
|
+
agent_app = FastAgent("FastAgent Example")
|
|
114
|
+
# Uncomment the below to disable human input callback tool
|
|
115
|
+
# agent_app.app._human_input_callback = None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# Define the agent
|
|
119
|
+
@agent_app.agent(servers=["fetch"])
|
|
120
|
+
# @agent_app.agent(servers=["fetch"])
|
|
121
|
+
async def main():
|
|
122
|
+
# use the --model= command line switch to specify model
|
|
123
|
+
async with agent_app.run() as agent:
|
|
124
|
+
await agent()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
if __name__ == "__main__":
|
|
128
|
+
asyncio.run(main())
|
|
129
|
+
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def find_gitignore(path: Path) -> bool:
|
|
134
|
+
"""Check if a .gitignore file exists in this directory or any parent."""
|
|
135
|
+
current = path
|
|
136
|
+
while current != current.parent: # Stop at root directory
|
|
137
|
+
if (current / ".gitignore").exists():
|
|
138
|
+
return True
|
|
139
|
+
current = current.parent
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def create_file(path: Path, content: str, force: bool = False) -> bool:
|
|
144
|
+
"""Create a file with given content if it doesn't exist or force is True."""
|
|
145
|
+
if path.exists() and not force:
|
|
146
|
+
should_overwrite = Confirm.ask(
|
|
147
|
+
f"[yellow]Warning:[/yellow] {path} already exists. Overwrite?",
|
|
148
|
+
default=False,
|
|
149
|
+
)
|
|
150
|
+
if not should_overwrite:
|
|
151
|
+
console.print(f"Skipping {path}")
|
|
152
|
+
return False
|
|
153
|
+
|
|
154
|
+
path.write_text(content.strip() + "\n")
|
|
155
|
+
console.print(f"[green]Created[/green] {path}")
|
|
156
|
+
return True
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@app.callback(invoke_without_command=True)
|
|
160
|
+
def init(
|
|
161
|
+
config_dir: str = typer.Option(
|
|
162
|
+
".",
|
|
163
|
+
"--config-dir",
|
|
164
|
+
"-c",
|
|
165
|
+
help="Directory where configuration files will be created",
|
|
166
|
+
),
|
|
167
|
+
force: bool = typer.Option(
|
|
168
|
+
False, "--force", "-f", help="Force overwrite existing files"
|
|
169
|
+
),
|
|
170
|
+
):
|
|
171
|
+
"""Initialize a new FastAgent project with configuration files and example agent."""
|
|
172
|
+
|
|
173
|
+
config_path = Path(config_dir).resolve()
|
|
174
|
+
if not config_path.exists():
|
|
175
|
+
should_create = Confirm.ask(
|
|
176
|
+
f"Directory {config_path} does not exist. Create it?", default=True
|
|
177
|
+
)
|
|
178
|
+
if should_create:
|
|
179
|
+
config_path.mkdir(parents=True)
|
|
180
|
+
else:
|
|
181
|
+
raise typer.Abort()
|
|
182
|
+
|
|
183
|
+
# Check for existing .gitignore
|
|
184
|
+
needs_gitignore = not find_gitignore(config_path)
|
|
185
|
+
|
|
186
|
+
console.print("\n[bold]FastAgent Setup[/bold]\n")
|
|
187
|
+
console.print("This will create the following files:")
|
|
188
|
+
console.print(f" - {config_path}/fastagent.config.yaml")
|
|
189
|
+
console.print(f" - {config_path}/fastagent.secrets.yaml")
|
|
190
|
+
console.print(f" - {config_path}/agent.py")
|
|
191
|
+
if needs_gitignore:
|
|
192
|
+
console.print(f" - {config_path}/.gitignore")
|
|
193
|
+
|
|
194
|
+
if not Confirm.ask("\nContinue?", default=True):
|
|
195
|
+
raise typer.Abort()
|
|
196
|
+
|
|
197
|
+
# Create configuration files
|
|
198
|
+
created = []
|
|
199
|
+
if create_file(
|
|
200
|
+
config_path / "fastagent.config.yaml", FASTAGENT_CONFIG_TEMPLATE, force
|
|
201
|
+
):
|
|
202
|
+
created.append("fastagent.yaml")
|
|
203
|
+
|
|
204
|
+
if create_file(
|
|
205
|
+
config_path / "fastagent.secrets.yaml", FASTAGENT_SECRETS_TEMPLATE, force
|
|
206
|
+
):
|
|
207
|
+
created.append("fastagent.secrets.yaml")
|
|
208
|
+
|
|
209
|
+
if create_file(config_path / "agent.py", AGENT_EXAMPLE_TEMPLATE, force):
|
|
210
|
+
created.append("agent.py")
|
|
211
|
+
|
|
212
|
+
# Only create .gitignore if none exists in parent directories
|
|
213
|
+
if needs_gitignore and create_file(
|
|
214
|
+
config_path / ".gitignore", GITIGNORE_TEMPLATE, force
|
|
215
|
+
):
|
|
216
|
+
created.append(".gitignore")
|
|
217
|
+
|
|
218
|
+
if created:
|
|
219
|
+
console.print("\n[green]Setup completed successfully![/green]")
|
|
220
|
+
if "fastagent-secrets.yaml" in created:
|
|
221
|
+
console.print("\n[yellow]Important:[/yellow] Remember to:")
|
|
222
|
+
console.print("1. Add your API keys to fastagent-secrets.yaml")
|
|
223
|
+
console.print(
|
|
224
|
+
"2. Keep fastagent-secrets.yaml secure and never commit it to version control"
|
|
225
|
+
)
|
|
226
|
+
console.print("\nTo get started, run:")
|
|
227
|
+
console.print(" uv run agent.py")
|
|
228
|
+
else:
|
|
229
|
+
console.print("\n[yellow]No files were created or modified.[/yellow]")
|
mcp_agent/cli/main.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Main CLI entry point for MCP Agent."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich.table import Table
|
|
6
|
+
from mcp_agent.cli.terminal import Application
|
|
7
|
+
from mcp_agent.cli.commands import setup, bootstrap
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(
|
|
10
|
+
help="MCP Agent CLI - Build effective agents using Model Context Protocol",
|
|
11
|
+
add_completion=False, # We'll add this later when we have more commands
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
# Subcommands
|
|
15
|
+
app.add_typer(setup.app, name="setup", help="Set up a new agent project")
|
|
16
|
+
app.add_typer(bootstrap.app, name="bootstrap", help="Create example applications")
|
|
17
|
+
|
|
18
|
+
# Shared application context
|
|
19
|
+
application = Application()
|
|
20
|
+
console = Console()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def show_welcome():
|
|
24
|
+
"""Show a welcome message with available commands."""
|
|
25
|
+
console.print("\n[bold]Welcome to MCP Agent![/bold]")
|
|
26
|
+
console.print("Build effective agents using Model Context Protocol (MCP)")
|
|
27
|
+
|
|
28
|
+
# Create a table for commands
|
|
29
|
+
table = Table(title="\nAvailable Commands")
|
|
30
|
+
table.add_column("Command", style="green")
|
|
31
|
+
table.add_column("Description")
|
|
32
|
+
|
|
33
|
+
table.add_row("setup", "Set up a new agent project with configuration files")
|
|
34
|
+
table.add_row(
|
|
35
|
+
"bootstrap", "Create example applications (decorator, researcher, etc.)"
|
|
36
|
+
)
|
|
37
|
+
# table.add_row("config", "Manage agent configuration settings")
|
|
38
|
+
|
|
39
|
+
console.print(table)
|
|
40
|
+
|
|
41
|
+
console.print("\n[bold]Getting Started:[/bold]")
|
|
42
|
+
console.print("1. Set up a new project:")
|
|
43
|
+
console.print(" mcp-agent setup")
|
|
44
|
+
console.print("\n2. Try an example:")
|
|
45
|
+
console.print(" mcp-agent bootstrap create decorator")
|
|
46
|
+
console.print("\nUse --help with any command for more information")
|
|
47
|
+
console.print("Example: mcp-agent bootstrap --help")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@app.callback(invoke_without_command=True)
|
|
51
|
+
def main(
|
|
52
|
+
ctx: typer.Context,
|
|
53
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose mode"),
|
|
54
|
+
quiet: bool = typer.Option(False, "--quiet", "-q", help="Disable output"),
|
|
55
|
+
color: bool = typer.Option(
|
|
56
|
+
True, "--color/--no-color", help="Enable/disable color output"
|
|
57
|
+
),
|
|
58
|
+
):
|
|
59
|
+
"""MCP Agent CLI - Build effective agents using Model Context Protocol (MCP).
|
|
60
|
+
|
|
61
|
+
Use --help with any command for detailed usage information.
|
|
62
|
+
"""
|
|
63
|
+
application.verbosity = 1 if verbose else 0 if not quiet else -1
|
|
64
|
+
application.console = application.console if color else None
|
|
65
|
+
|
|
66
|
+
# Show welcome message if no command was invoked
|
|
67
|
+
if ctx.invoked_subcommand is None:
|
|
68
|
+
show_welcome()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from mcp_agent.console import console, error_console
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Application:
|
|
5
|
+
def __init__(self, verbosity: int = 0, enable_color: bool = True):
|
|
6
|
+
self.verbosity = verbosity
|
|
7
|
+
# Use the central console instances, respecting color setting
|
|
8
|
+
if not enable_color:
|
|
9
|
+
# Create new instances without color if color is disabled
|
|
10
|
+
self.console = console.__class__(color_system=None)
|
|
11
|
+
self.error_console = error_console.__class__(color_system=None, stderr=True)
|
|
12
|
+
else:
|
|
13
|
+
self.console = console
|
|
14
|
+
self.error_console = error_console
|
|
15
|
+
|
|
16
|
+
def log(self, message: str, level: str = "info"):
|
|
17
|
+
if level == "info" or (level == "debug" and self.verbosity > 0):
|
|
18
|
+
if level == "error":
|
|
19
|
+
self.error_console.print(f"[{level.upper()}] {message}")
|
|
20
|
+
else:
|
|
21
|
+
self.console.print(f"[{level.upper()}] {message}")
|
|
22
|
+
|
|
23
|
+
def status(self, message: str):
|
|
24
|
+
return self.console.status(f"[bold cyan]{message}[/bold cyan]")
|