fast-agent-mcp 0.0.7__py3-none-any.whl → 0.0.8__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.

Files changed (31) hide show
  1. {fast_agent_mcp-0.0.7.dist-info → fast_agent_mcp-0.0.8.dist-info}/METADATA +22 -57
  2. {fast_agent_mcp-0.0.7.dist-info → fast_agent_mcp-0.0.8.dist-info}/RECORD +29 -23
  3. mcp_agent/agents/agent.py +8 -4
  4. mcp_agent/app.py +5 -1
  5. mcp_agent/cli/commands/bootstrap.py +180 -121
  6. mcp_agent/cli/commands/setup.py +20 -16
  7. mcp_agent/core/__init__.py +0 -0
  8. mcp_agent/core/exceptions.py +47 -0
  9. mcp_agent/core/fastagent.py +176 -85
  10. mcp_agent/core/server_validation.py +44 -0
  11. mcp_agent/event_progress.py +4 -1
  12. mcp_agent/logging/rich_progress.py +11 -0
  13. mcp_agent/mcp/mcp_connection_manager.py +11 -2
  14. mcp_agent/resources/examples/data-analysis/analysis.py +35 -0
  15. mcp_agent/resources/examples/data-analysis/fastagent.config.yaml +20 -0
  16. mcp_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +1471 -0
  17. mcp_agent/resources/examples/workflows/chaining.py +31 -0
  18. mcp_agent/resources/examples/{decorator/optimizer.py → workflows/evaluator.py} +7 -10
  19. mcp_agent/resources/examples/workflows/human_input.py +26 -0
  20. mcp_agent/resources/examples/{decorator → workflows}/orchestrator.py +20 -11
  21. mcp_agent/resources/examples/{decorator → workflows}/parallel.py +14 -18
  22. mcp_agent/resources/examples/{decorator → workflows}/router.py +9 -10
  23. mcp_agent/workflows/llm/augmented_llm_anthropic.py +48 -12
  24. mcp_agent/workflows/llm/augmented_llm_openai.py +38 -9
  25. mcp_agent/resources/examples/decorator/main.py +0 -26
  26. mcp_agent/resources/examples/decorator/tiny.py +0 -22
  27. {fast_agent_mcp-0.0.7.dist-info → fast_agent_mcp-0.0.8.dist-info}/WHEEL +0 -0
  28. {fast_agent_mcp-0.0.7.dist-info → fast_agent_mcp-0.0.8.dist-info}/entry_points.txt +0 -0
  29. {fast_agent_mcp-0.0.7.dist-info → fast_agent_mcp-0.0.8.dist-info}/licenses/LICENSE +0 -0
  30. /mcp_agent/resources/examples/mcp_researcher/{main-evalopt.py → researcher-eval.py} +0 -0
  31. /mcp_agent/resources/examples/mcp_researcher/{main.py → researcher.py} +0 -0
@@ -8,40 +8,45 @@ from rich.table import Table
8
8
  from rich.panel import Panel
9
9
 
10
10
  app = typer.Typer(
11
- help="Create example applications and learn MCP Agent patterns",
12
- no_args_is_help=True,
11
+ help="Create example applications",
12
+ no_args_is_help=False, # Allow showing our custom help instead
13
13
  )
14
14
  console = Console()
15
15
 
16
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
- """,
17
+ "workflow": {
18
+ "description": "Example workflows, demonstrating each of the patterns in Anthropic's\n"
19
+ "'Building Effective Agents' paper. Some agents use the 'fetch'\n"
20
+ "and filesystem MCP Servers.",
26
21
  "files": [
27
- "main.py",
28
- "optimizer.py",
22
+ "chaining.py",
23
+ "evaluator.py",
24
+ "human_input.py",
29
25
  "orchestrator.py",
30
26
  "parallel.py",
31
27
  "router.py",
32
- "tiny.py",
33
28
  ],
29
+ "create_subdir": False,
34
30
  },
35
31
  "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"],
32
+ "description": "Research agent example with additional evaluation/optimization\n"
33
+ "example. Uses Brave Search and Docker MCP Servers.\n"
34
+ "Creates examples in a 'researcher' subdirectory.",
35
+ "files": [
36
+ "researcher.py",
37
+ "researcher-eval.py",
38
+ "mcp_agent.secrets.yaml.example",
39
+ ],
40
+ "create_subdir": True,
41
+ },
42
+ "data-analysis": {
43
+ "description": "Data analysis agent examples that demonstrate working with\n"
44
+ "datasets, performing statistical analysis, and generating visualizations.\n"
45
+ "Creates examples in a 'data-analysis' subdirectory with mount-point for data.\n"
46
+ "Uses MCP 'roots' feature for mapping",
47
+ "files": ["analysis.py", "fastagent.config.yaml"],
48
+ "mount_point_files": ["WA_Fn-UseC_-HR-Employee-Attrition.csv"],
49
+ "create_subdir": True,
45
50
  },
46
51
  }
47
52
 
@@ -52,19 +57,35 @@ def copy_example_files(
52
57
  """Copy example files from resources to target directory."""
53
58
  created = []
54
59
 
55
- # During development, use the source directory
60
+ # Determine if we should create a subdirectory for this example type
61
+ example_info = EXAMPLE_TYPES[example_type]
62
+ if example_info["create_subdir"]:
63
+ target_dir = target_dir / example_type
64
+ if not target_dir.exists():
65
+ target_dir.mkdir(parents=True)
66
+ console.print(f"Created subdirectory: {target_dir}")
67
+
68
+ # Create mount-point directory if needed
69
+ mount_point_files = example_info.get("mount_point_files", [])
70
+ if mount_point_files:
71
+ mount_point_dir = target_dir / "mount-point"
72
+ if not mount_point_dir.exists():
73
+ mount_point_dir.mkdir(parents=True)
74
+ console.print(f"Created mount-point directory: {mount_point_dir}")
75
+
76
+ # Use the resources directory from the package
56
77
  source_dir = (
57
78
  Path(__file__).parent.parent.parent
58
79
  / "resources"
59
80
  / "examples"
60
- / ("decorator" if example_type == "decorator" else "mcp_researcher")
81
+ / ("workflows" if example_type == "workflow" else f"{example_type}")
61
82
  )
62
83
 
63
84
  if not source_dir.exists():
64
85
  console.print(f"[red]Error: Source directory not found: {source_dir}[/red]")
65
86
  return created
66
87
 
67
- for filename in EXAMPLE_TYPES[example_type]["files"]:
88
+ for filename in example_info["files"]:
68
89
  source = source_dir / filename
69
90
  target = target_dir / filename
70
91
 
@@ -78,125 +99,143 @@ def copy_example_files(
78
99
  continue
79
100
 
80
101
  shutil.copy2(source, target)
81
- created.append(filename)
82
- console.print(f"[green]Created[/green] {filename}")
102
+ created.append(str(target.relative_to(target_dir.parent)))
103
+ console.print(f"[green]Created[/green] {created[-1]}")
83
104
 
84
105
  except Exception as e:
85
106
  console.print(f"[red]Error copying {filename}: {str(e)}[/red]")
86
107
 
108
+ # Copy mount-point files if any
109
+ if mount_point_files:
110
+ source_mount_point = source_dir / "mount-point"
111
+ for filename in mount_point_files:
112
+ source = source_mount_point / filename
113
+ target = mount_point_dir / filename
114
+
115
+ try:
116
+ if not source.exists():
117
+ console.print(f"[red]Error: Source file not found: {source}[/red]")
118
+ continue
119
+
120
+ if target.exists() and not force:
121
+ console.print(
122
+ f"[yellow]Skipping[/yellow] mount-point/{filename} (already exists)"
123
+ )
124
+ continue
125
+
126
+ shutil.copy2(source, target)
127
+ created.append(f"{example_type}/mount-point/{filename}")
128
+ console.print(f"[green]Created[/green] mount-point/{filename}")
129
+
130
+ except Exception as e:
131
+ console.print(
132
+ f"[red]Error copying mount-point/{filename}: {str(e)}[/red]"
133
+ )
134
+
87
135
  return created
88
136
 
89
137
 
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")
138
+ def show_overview():
139
+ """Display an overview of available examples in a nicely formatted table."""
140
+ console.print("\n[bold cyan]FastAgent Example Applications[/bold cyan]")
141
+ console.print("Build agents and compose workflows through practical examples\n")
94
142
 
95
- # Create a table for the examples
96
- table = Table(title="Available Examples")
97
- table.add_column("Example", style="green")
143
+ # Create a table for better organization
144
+ table = Table(
145
+ show_header=True, header_style="bold magenta", box=None, padding=(0, 2)
146
+ )
147
+ table.add_column("Example")
98
148
  table.add_column("Description")
99
- table.add_column("Files", style="blue")
149
+ table.add_column("Files")
100
150
 
101
151
  for name, info in EXAMPLE_TYPES.items():
102
- table.add_row(name, info["description"], "\n".join(info["files"]))
152
+ files_list = "\n".join(f"• {f}" for f in info["files"])
153
+ if "mount_point_files" in info:
154
+ files_list += "\n[blue]mount-point:[/blue]\n" + "\n".join(
155
+ f"• {f}" for f in info["mount_point_files"]
156
+ )
157
+ table.add_row(f"[green]{name}[/green]", info["description"], files_list)
103
158
 
104
159
  console.print(table)
105
160
 
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"
161
+ # Show usage instructions in a panel
162
+ usage_text = (
163
+ "[bold]Commands:[/bold]\n"
164
+ " fastagent bootstrap workflow DIR Create workflow examples in DIR\n"
165
+ " fastagent bootstrap researcher DIR Create researcher example in 'researcher' subdirectory\n"
166
+ " fastagent bootstrap data-analysis DIR Create data analysis examples in 'data-analysis' subdirectory\n\n"
167
+ "[bold]Options:[/bold]\n"
168
+ " --force Overwrite existing files\n\n"
169
+ "[bold]Examples:[/bold]\n"
170
+ " fastagent bootstrap workflow . Create in current directory\n"
171
+ " fastagent bootstrap researcher . Create in researcher subdirectory\n"
172
+ " fastagent bootstrap data-analysis . --force Force overwrite files in data-analysis subdirectory"
121
173
  )
174
+ console.print(Panel(usage_text, title="Usage", border_style="blue"))
122
175
 
123
176
 
124
- @app.callback(invoke_without_command=True)
125
- def main(ctx: typer.Context):
126
- """Bootstrap example applications to learn MCP Agent patterns.
177
+ @app.command()
178
+ def workflow(
179
+ directory: Path = typer.Argument(
180
+ Path("."),
181
+ help="Directory where workflow examples will be created",
182
+ ),
183
+ force: bool = typer.Option(
184
+ False, "--force", "-f", help="Force overwrite existing files"
185
+ ),
186
+ ):
187
+ """Create workflow pattern examples."""
188
+ target_dir = directory.resolve()
189
+ if not target_dir.exists():
190
+ target_dir.mkdir(parents=True)
191
+ console.print(f"Created directory: {target_dir}")
127
192
 
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()
193
+ created = copy_example_files("workflow", target_dir, force)
194
+ _show_completion_message("workflow", created)
133
195
 
134
196
 
135
197
  @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"
198
+ def researcher(
199
+ directory: Path = typer.Argument(
200
+ Path("."),
201
+ help="Directory where researcher examples will be created (in 'researcher' subdirectory)",
142
202
  ),
143
203
  force: bool = typer.Option(
144
204
  False, "--force", "-f", help="Force overwrite existing files"
145
205
  ),
146
206
  ):
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()
207
+ """Create researcher pattern examples."""
208
+ target_dir = directory.resolve()
168
209
  if not target_dir.exists():
169
210
  target_dir.mkdir(parents=True)
170
211
  console.print(f"Created directory: {target_dir}")
171
212
 
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
- )
213
+ created = copy_example_files("researcher", target_dir, force)
214
+ _show_completion_message("researcher", created)
181
215
 
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
216
 
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)
217
+ @app.command()
218
+ def data_analysis(
219
+ directory: Path = typer.Argument(
220
+ Path("."),
221
+ help="Directory where data analysis examples will be created (creates 'data-analysis' subdirectory with mount-point)",
222
+ ),
223
+ force: bool = typer.Option(
224
+ False, "--force", "-f", help="Force overwrite existing files"
225
+ ),
226
+ ):
227
+ """Create data analysis examples with sample dataset."""
228
+ target_dir = directory.resolve()
229
+ if not target_dir.exists():
230
+ target_dir.mkdir(parents=True)
231
+ console.print(f"Created directory: {target_dir}")
232
+
233
+ created = copy_example_files("data-analysis", target_dir, force)
234
+ _show_completion_message("data-analysis", created)
197
235
 
198
- created = copy_example_files(example_type, target_dir, force)
199
236
 
237
+ def _show_completion_message(example_type: str, created: list[str]):
238
+ """Show completion message and next steps."""
200
239
  if created:
201
240
  console.print("\n[green]Setup completed successfully![/green]")
202
241
  console.print("\nCreated files:")
@@ -204,18 +243,38 @@ def create(
204
243
  console.print(f" - {f}")
205
244
 
206
245
  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")
246
+ if example_type == "workflow":
247
+ console.print("1. Review chaining.py for the basic workflow example")
248
+ console.print("2. Check other examples:")
212
249
  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")
250
+ console.print(" - router.py: Route requests between agents")
251
+ console.print(" - evaluator.py: Add evaluation capabilities")
252
+ console.print(" - human_input.py: Incorporate human feedback")
253
+ console.print("3. Run an example with: uv run <example>.py")
216
254
  console.print(
217
- "2. Try main-evalopt.py for the evaluation optimization version"
255
+ "4. Try a different model with --model=<model>, or update the agent config"
218
256
  )
219
- console.print("3. Run with: python main.py or python main-evalopt.py")
257
+
258
+ elif example_type == "researcher":
259
+ console.print(
260
+ "1. Set up the Brave MCP Server (get an API key from https://brave.com/search/api/)"
261
+ )
262
+ console.print("2. Try `uv run researcher.py` for the basic version")
263
+ console.print(
264
+ "3. Try `uv run researcher-eval.py` for the eval/optimize version"
265
+ )
266
+ elif example_type == "data-analysis":
267
+ console.print(
268
+ "1. Run uv `analysis.py` to perform data analysis and visualization"
269
+ )
270
+ console.print("2. The dataset is available in the mount-point directory:")
271
+ console.print(" - mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv")
220
272
  else:
221
273
  console.print("\n[yellow]No files were created.[/yellow]")
274
+
275
+
276
+ @app.callback(invoke_without_command=True)
277
+ def main(ctx: typer.Context):
278
+ """Create example applications and learn FastAgent patterns."""
279
+ if ctx.invoked_subcommand is None:
280
+ show_overview()
@@ -22,28 +22,31 @@ FASTAGENT_CONFIG_TEMPLATE = """
22
22
  default_model: sonnet
23
23
 
24
24
  # Logging and Console Configuration:
25
- logging:
25
+ logger:
26
26
  # level: "debug" | "info" | "warning" | "error"
27
27
  # type: "none" | "console" | "file" | "http"
28
28
  # path: "/path/to/logfile.jsonl"
29
29
 
30
30
 
31
31
  # Switch the progress display on or off
32
- # progress_display: true
32
+ progress_display: true
33
33
 
34
34
  # Show chat User/Assistant messages on the console
35
- # show_chat: true
35
+ show_chat: true
36
36
  # Show tool calls on the console
37
- # show_tools: true
37
+ show_tools: true
38
38
  # Truncate long tool responses on the console
39
- # truncate_tools: true
39
+ truncate_tools: true
40
40
 
41
41
  # MCP Servers
42
42
  mcp:
43
43
  servers:
44
44
  fetch:
45
45
  command: "uvx"
46
- args: ["mcp-server-fetch"]
46
+ args: ["mcp-server-fetch"]
47
+ filesystem:
48
+ command: "npx"
49
+ args: ["-y", "@modelcontextprotocol/server-filesystem", "."]
47
50
 
48
51
  """
49
52
 
@@ -51,6 +54,8 @@ FASTAGENT_SECRETS_TEMPLATE = """
51
54
  # FastAgent Secrets Configuration
52
55
  # WARNING: Keep this file secure and never commit to version control
53
56
 
57
+ # Alternatively set OPENAI_API_KEY and ANTHROPIC_API_KEY environment variables. Config file takes precedence.
58
+
54
59
  openai:
55
60
  api_key: <your-api-key-here>
56
61
  anthropic:
@@ -110,17 +115,14 @@ import asyncio
110
115
  from mcp_agent.core.fastagent import FastAgent
111
116
 
112
117
  # 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
118
+ fast = FastAgent("FastAgent Example")
116
119
 
117
120
 
118
121
  # Define the agent
119
- @agent_app.agent(servers=["fetch"])
120
- # @agent_app.agent(servers=["fetch"])
122
+ @fast.agent(servers=["fetch"])
121
123
  async def main():
122
- # use the --model= command line switch to specify model
123
- async with agent_app.run() as agent:
124
+ # use the --model command line switch or agent arguments to change model
125
+ async with fast.run() as agent:
124
126
  await agent()
125
127
 
126
128
 
@@ -217,11 +219,13 @@ def init(
217
219
 
218
220
  if created:
219
221
  console.print("\n[green]Setup completed successfully![/green]")
220
- if "fastagent-secrets.yaml" in created:
222
+ if "fastagent.secrets.yaml" in created:
221
223
  console.print("\n[yellow]Important:[/yellow] Remember to:")
222
- console.print("1. Add your API keys to fastagent-secrets.yaml")
223
224
  console.print(
224
- "2. Keep fastagent-secrets.yaml secure and never commit it to version control"
225
+ "1. Add your API keys to fastagent-secrets.yaml or set OPENAI_API_KEY and ANTHROPIC_API_KEY environment variables"
226
+ )
227
+ console.print(
228
+ "2. Keep fastagent.secrets.yaml secure and never commit it to version control"
225
229
  )
226
230
  console.print("\nTo get started, run:")
227
231
  console.print(" uv run agent.py")
File without changes
@@ -0,0 +1,47 @@
1
+ """
2
+ Custom exceptions for the FastAgent framework.
3
+ Enables user-friendly error handling for common issues.
4
+ """
5
+
6
+
7
+ class FastAgentError(Exception):
8
+ """Base exception class for FastAgent errors"""
9
+
10
+ def __init__(self, message: str, details: str = ""):
11
+ self.message = message
12
+ self.details = details
13
+ super().__init__(f"{message}\n\n{details}" if details else message)
14
+
15
+
16
+ class ServerConfigError(FastAgentError):
17
+ """Raised when there are issues with MCP server configuration
18
+ Example: Server name referenced in agent.servers[] but not defined in config
19
+ """
20
+
21
+ def __init__(self, message: str, details: str = ""):
22
+ super().__init__(message, details)
23
+
24
+
25
+ class AgentConfigError(FastAgentError):
26
+ """Raised when there are issues with Agent or Workflow configuration
27
+ Example: Parallel fan-in references unknown agent
28
+ """
29
+
30
+ def __init__(self, message: str, details: str = ""):
31
+ super().__init__(message, details)
32
+
33
+
34
+ class ProviderKeyError(FastAgentError):
35
+ """Raised when there are issues with LLM provider API keys
36
+ Example: OpenAI/Anthropic key not configured but model requires it
37
+ """
38
+
39
+ def __init__(self, message: str, details: str = ""):
40
+ super().__init__(message, details)
41
+
42
+
43
+ class ServerInitializationError(FastAgentError):
44
+ """Raised when a server fails to initialize properly."""
45
+
46
+ def __init__(self, message: str, details: str = ""):
47
+ super().__init__(message, details)