fast-agent-mcp 0.1.11__py3-none-any.whl → 0.1.13__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.
- {fast_agent_mcp-0.1.11.dist-info → fast_agent_mcp-0.1.13.dist-info}/METADATA +1 -1
- fast_agent_mcp-0.1.13.dist-info/RECORD +164 -0
- mcp_agent/agents/agent.py +37 -102
- mcp_agent/app.py +16 -27
- mcp_agent/cli/commands/bootstrap.py +22 -52
- mcp_agent/cli/commands/config.py +4 -4
- mcp_agent/cli/commands/setup.py +11 -26
- mcp_agent/cli/main.py +6 -9
- mcp_agent/cli/terminal.py +2 -2
- mcp_agent/config.py +1 -5
- mcp_agent/context.py +13 -26
- mcp_agent/context_dependent.py +3 -7
- mcp_agent/core/agent_app.py +46 -122
- mcp_agent/core/agent_types.py +29 -2
- mcp_agent/core/agent_utils.py +3 -5
- mcp_agent/core/decorators.py +6 -14
- mcp_agent/core/enhanced_prompt.py +25 -52
- mcp_agent/core/error_handling.py +1 -1
- mcp_agent/core/exceptions.py +8 -8
- mcp_agent/core/factory.py +30 -72
- mcp_agent/core/fastagent.py +48 -88
- mcp_agent/core/mcp_content.py +10 -19
- mcp_agent/core/prompt.py +8 -15
- mcp_agent/core/proxies.py +34 -25
- mcp_agent/core/request_params.py +46 -0
- mcp_agent/core/types.py +6 -6
- mcp_agent/core/validation.py +16 -16
- mcp_agent/executor/decorator_registry.py +11 -23
- mcp_agent/executor/executor.py +8 -17
- mcp_agent/executor/task_registry.py +2 -4
- mcp_agent/executor/temporal.py +28 -74
- mcp_agent/executor/workflow.py +3 -5
- mcp_agent/executor/workflow_signal.py +17 -29
- mcp_agent/human_input/handler.py +4 -9
- mcp_agent/human_input/types.py +2 -3
- mcp_agent/logging/events.py +1 -5
- mcp_agent/logging/json_serializer.py +7 -6
- mcp_agent/logging/listeners.py +20 -23
- mcp_agent/logging/logger.py +15 -17
- mcp_agent/logging/rich_progress.py +10 -8
- mcp_agent/logging/tracing.py +4 -6
- mcp_agent/logging/transport.py +24 -24
- mcp_agent/mcp/gen_client.py +4 -12
- mcp_agent/mcp/interfaces.py +107 -88
- mcp_agent/mcp/mcp_agent_client_session.py +11 -19
- mcp_agent/mcp/mcp_agent_server.py +8 -10
- mcp_agent/mcp/mcp_aggregator.py +49 -122
- mcp_agent/mcp/mcp_connection_manager.py +16 -37
- mcp_agent/mcp/prompt_message_multipart.py +12 -18
- mcp_agent/mcp/prompt_serialization.py +13 -38
- mcp_agent/mcp/prompts/prompt_load.py +99 -0
- mcp_agent/mcp/prompts/prompt_server.py +21 -128
- mcp_agent/mcp/prompts/prompt_template.py +20 -42
- mcp_agent/mcp/resource_utils.py +8 -17
- mcp_agent/mcp/sampling.py +62 -64
- mcp_agent/mcp/stdio.py +11 -8
- mcp_agent/mcp_server/__init__.py +1 -1
- mcp_agent/mcp_server/agent_server.py +10 -17
- mcp_agent/mcp_server_registry.py +13 -35
- mcp_agent/resources/examples/data-analysis/analysis-campaign.py +1 -1
- mcp_agent/resources/examples/data-analysis/analysis.py +1 -1
- mcp_agent/resources/examples/data-analysis/slides.py +110 -0
- mcp_agent/resources/examples/internal/agent.py +2 -1
- mcp_agent/resources/examples/internal/job.py +2 -1
- mcp_agent/resources/examples/internal/prompt_category.py +1 -1
- mcp_agent/resources/examples/internal/prompt_sizing.py +3 -5
- mcp_agent/resources/examples/internal/sizer.py +2 -1
- mcp_agent/resources/examples/internal/social.py +2 -1
- mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +1 -1
- mcp_agent/resources/examples/prompting/__init__.py +1 -1
- mcp_agent/resources/examples/prompting/agent.py +2 -1
- mcp_agent/resources/examples/prompting/image_server.py +5 -11
- mcp_agent/resources/examples/researcher/researcher-eval.py +1 -1
- mcp_agent/resources/examples/researcher/researcher-imp.py +3 -4
- mcp_agent/resources/examples/researcher/researcher.py +2 -1
- mcp_agent/resources/examples/workflows/agent_build.py +2 -1
- mcp_agent/resources/examples/workflows/chaining.py +2 -1
- mcp_agent/resources/examples/workflows/evaluator.py +2 -1
- mcp_agent/resources/examples/workflows/human_input.py +2 -1
- mcp_agent/resources/examples/workflows/orchestrator.py +2 -1
- mcp_agent/resources/examples/workflows/parallel.py +2 -1
- mcp_agent/resources/examples/workflows/router.py +2 -1
- mcp_agent/resources/examples/workflows/sse.py +1 -1
- mcp_agent/telemetry/usage_tracking.py +2 -1
- mcp_agent/ui/console_display.py +17 -41
- mcp_agent/workflows/embedding/embedding_base.py +1 -4
- mcp_agent/workflows/embedding/embedding_cohere.py +2 -2
- mcp_agent/workflows/embedding/embedding_openai.py +4 -13
- mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +23 -57
- mcp_agent/workflows/intent_classifier/intent_classifier_base.py +5 -8
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +7 -11
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +4 -8
- mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +4 -8
- mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +11 -22
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +3 -3
- mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +4 -6
- mcp_agent/workflows/llm/anthropic_utils.py +8 -29
- mcp_agent/workflows/llm/augmented_llm.py +94 -332
- mcp_agent/workflows/llm/augmented_llm_anthropic.py +43 -76
- mcp_agent/workflows/llm/augmented_llm_openai.py +46 -100
- mcp_agent/workflows/llm/augmented_llm_passthrough.py +42 -20
- mcp_agent/workflows/llm/augmented_llm_playback.py +8 -6
- mcp_agent/workflows/llm/memory.py +103 -0
- mcp_agent/workflows/llm/model_factory.py +9 -21
- mcp_agent/workflows/llm/openai_utils.py +1 -1
- mcp_agent/workflows/llm/prompt_utils.py +39 -27
- mcp_agent/workflows/llm/providers/multipart_converter_anthropic.py +246 -184
- mcp_agent/workflows/llm/providers/multipart_converter_openai.py +212 -202
- mcp_agent/workflows/llm/providers/openai_multipart.py +19 -61
- mcp_agent/workflows/llm/providers/sampling_converter_anthropic.py +11 -212
- mcp_agent/workflows/llm/providers/sampling_converter_openai.py +13 -215
- mcp_agent/workflows/llm/sampling_converter.py +117 -0
- mcp_agent/workflows/llm/sampling_format_converter.py +12 -29
- mcp_agent/workflows/orchestrator/orchestrator.py +24 -67
- mcp_agent/workflows/orchestrator/orchestrator_models.py +14 -40
- mcp_agent/workflows/parallel/fan_in.py +17 -47
- mcp_agent/workflows/parallel/fan_out.py +6 -12
- mcp_agent/workflows/parallel/parallel_llm.py +9 -26
- mcp_agent/workflows/router/router_base.py +29 -59
- mcp_agent/workflows/router/router_embedding.py +11 -25
- mcp_agent/workflows/router/router_embedding_cohere.py +2 -2
- mcp_agent/workflows/router/router_embedding_openai.py +2 -2
- mcp_agent/workflows/router/router_llm.py +12 -28
- mcp_agent/workflows/swarm/swarm.py +20 -48
- mcp_agent/workflows/swarm/swarm_anthropic.py +2 -2
- mcp_agent/workflows/swarm/swarm_openai.py +2 -2
- fast_agent_mcp-0.1.11.dist-info/RECORD +0 -160
- mcp_agent/workflows/llm/llm_selector.py +0 -345
- {fast_agent_mcp-0.1.11.dist-info → fast_agent_mcp-0.1.13.dist-info}/WHEEL +0 -0
- {fast_agent_mcp-0.1.11.dist-info → fast_agent_mcp-0.1.13.dist-info}/entry_points.txt +0 -0
- {fast_agent_mcp-0.1.11.dist-info → fast_agent_mcp-0.1.13.dist-info}/licenses/LICENSE +0 -0
@@ -2,10 +2,11 @@
|
|
2
2
|
|
3
3
|
import shutil
|
4
4
|
from pathlib import Path
|
5
|
+
|
5
6
|
import typer
|
6
7
|
from rich.console import Console
|
7
|
-
from rich.table import Table
|
8
8
|
from rich.panel import Panel
|
9
|
+
from rich.table import Table
|
9
10
|
|
10
11
|
app = typer.Typer(
|
11
12
|
help="Create example applications",
|
@@ -49,9 +50,7 @@ EXAMPLE_TYPES = {
|
|
49
50
|
}
|
50
51
|
|
51
52
|
|
52
|
-
def copy_example_files(
|
53
|
-
example_type: str, target_dir: Path, force: bool = False
|
54
|
-
) -> list[str]:
|
53
|
+
def copy_example_files(example_type: str, target_dir: Path, force: bool = False) -> list[str]:
|
55
54
|
"""Copy example files from resources to target directory."""
|
56
55
|
created = []
|
57
56
|
|
@@ -72,12 +71,7 @@ def copy_example_files(
|
|
72
71
|
console.print(f"Created mount-point directory: {mount_point_dir}")
|
73
72
|
|
74
73
|
# Use the resources directory from the package
|
75
|
-
source_dir = (
|
76
|
-
Path(__file__).parent.parent.parent
|
77
|
-
/ "resources"
|
78
|
-
/ "examples"
|
79
|
-
/ ("workflows" if example_type == "workflow" else f"{example_type}")
|
80
|
-
)
|
74
|
+
source_dir = Path(__file__).parent.parent.parent / "resources" / "examples" / ("workflows" if example_type == "workflow" else f"{example_type}")
|
81
75
|
|
82
76
|
if not source_dir.exists():
|
83
77
|
console.print(f"[red]Error: Source directory not found: {source_dir}[/red]")
|
@@ -116,9 +110,7 @@ def copy_example_files(
|
|
116
110
|
continue
|
117
111
|
|
118
112
|
if target.exists() and not force:
|
119
|
-
console.print(
|
120
|
-
f"[yellow]Skipping[/yellow] mount-point/{filename} (already exists)"
|
121
|
-
)
|
113
|
+
console.print(f"[yellow]Skipping[/yellow] mount-point/{filename} (already exists)")
|
122
114
|
continue
|
123
115
|
|
124
116
|
shutil.copy2(source, target)
|
@@ -126,22 +118,18 @@ def copy_example_files(
|
|
126
118
|
console.print(f"[green]Created[/green] mount-point/{filename}")
|
127
119
|
|
128
120
|
except Exception as e:
|
129
|
-
console.print(
|
130
|
-
f"[red]Error copying mount-point/{filename}: {str(e)}[/red]"
|
131
|
-
)
|
121
|
+
console.print(f"[red]Error copying mount-point/{filename}: {str(e)}[/red]")
|
132
122
|
|
133
123
|
return created
|
134
124
|
|
135
125
|
|
136
|
-
def show_overview():
|
126
|
+
def show_overview() -> None:
|
137
127
|
"""Display an overview of available examples in a nicely formatted table."""
|
138
128
|
console.print("\n[bold cyan]fast-agent Example Applications[/bold cyan]")
|
139
129
|
console.print("Build agents and compose workflows through practical examples\n")
|
140
130
|
|
141
131
|
# Create a table for better organization
|
142
|
-
table = Table(
|
143
|
-
show_header=True, header_style="bold magenta", box=None, padding=(0, 2)
|
144
|
-
)
|
132
|
+
table = Table(show_header=True, header_style="bold magenta", box=None, padding=(0, 2))
|
145
133
|
table.add_column("Example")
|
146
134
|
table.add_column("Description")
|
147
135
|
table.add_column("Files")
|
@@ -149,9 +137,7 @@ def show_overview():
|
|
149
137
|
for name, info in EXAMPLE_TYPES.items():
|
150
138
|
files_list = "\n".join(f"• {f}" for f in info["files"])
|
151
139
|
if "mount_point_files" in info:
|
152
|
-
files_list += "\n[blue]mount-point:[/blue]\n" + "\n".join(
|
153
|
-
f"• {f}" for f in info["mount_point_files"]
|
154
|
-
)
|
140
|
+
files_list += "\n[blue]mount-point:[/blue]\n" + "\n".join(f"• {f}" for f in info["mount_point_files"])
|
155
141
|
table.add_row(f"[green]{name}[/green]", info["description"], files_list)
|
156
142
|
|
157
143
|
console.print(table)
|
@@ -178,10 +164,8 @@ def workflow(
|
|
178
164
|
Path("."),
|
179
165
|
help="Directory where workflow examples will be created",
|
180
166
|
),
|
181
|
-
force: bool = typer.Option(
|
182
|
-
|
183
|
-
),
|
184
|
-
):
|
167
|
+
force: bool = typer.Option(False, "--force", "-f", help="Force overwrite existing files"),
|
168
|
+
) -> None:
|
185
169
|
"""Create workflow pattern examples."""
|
186
170
|
target_dir = directory.resolve()
|
187
171
|
if not target_dir.exists():
|
@@ -198,10 +182,8 @@ def researcher(
|
|
198
182
|
Path("."),
|
199
183
|
help="Directory where researcher examples will be created (in 'researcher' subdirectory)",
|
200
184
|
),
|
201
|
-
force: bool = typer.Option(
|
202
|
-
|
203
|
-
),
|
204
|
-
):
|
185
|
+
force: bool = typer.Option(False, "--force", "-f", help="Force overwrite existing files"),
|
186
|
+
) -> None:
|
205
187
|
"""Create researcher pattern examples."""
|
206
188
|
target_dir = directory.resolve()
|
207
189
|
if not target_dir.exists():
|
@@ -218,10 +200,8 @@ def data_analysis(
|
|
218
200
|
Path("."),
|
219
201
|
help="Directory where data analysis examples will be created (creates 'data-analysis' subdirectory with mount-point)",
|
220
202
|
),
|
221
|
-
force: bool = typer.Option(
|
222
|
-
|
223
|
-
),
|
224
|
-
):
|
203
|
+
force: bool = typer.Option(False, "--force", "-f", help="Force overwrite existing files"),
|
204
|
+
) -> None:
|
225
205
|
"""Create data analysis examples with sample dataset."""
|
226
206
|
target_dir = directory.resolve()
|
227
207
|
if not target_dir.exists():
|
@@ -232,7 +212,7 @@ def data_analysis(
|
|
232
212
|
_show_completion_message("data-analysis", created)
|
233
213
|
|
234
214
|
|
235
|
-
def _show_completion_message(example_type: str, created: list[str]):
|
215
|
+
def _show_completion_message(example_type: str, created: list[str]) -> None:
|
236
216
|
"""Show completion message and next steps."""
|
237
217
|
if created:
|
238
218
|
console.print("\n[green]Setup completed successfully![/green]")
|
@@ -249,33 +229,23 @@ def _show_completion_message(example_type: str, created: list[str]):
|
|
249
229
|
console.print(" - evaluator.py: Add evaluation capabilities")
|
250
230
|
console.print(" - human_input.py: Incorporate human feedback")
|
251
231
|
console.print("3. Run an example with: uv run <example>.py")
|
252
|
-
console.print(
|
253
|
-
"4. Try a different model with --model=<model>, or update the agent config"
|
254
|
-
)
|
232
|
+
console.print("4. Try a different model with --model=<model>, or update the agent config")
|
255
233
|
|
256
234
|
elif example_type == "researcher":
|
257
|
-
console.print(
|
258
|
-
"1. Set up the Brave MCP Server (get an API key from https://brave.com/search/api/)"
|
259
|
-
)
|
235
|
+
console.print("1. Set up the Brave MCP Server (get an API key from https://brave.com/search/api/)")
|
260
236
|
console.print("2. Try `uv run researcher.py` for the basic version")
|
261
|
-
console.print(
|
262
|
-
"3. Try `uv run researcher-eval.py` for the eval/optimize version"
|
263
|
-
)
|
237
|
+
console.print("3. Try `uv run researcher-eval.py` for the eval/optimize version")
|
264
238
|
elif example_type == "data-analysis":
|
265
|
-
console.print(
|
266
|
-
"1. Run uv `analysis.py` to perform data analysis and visualization"
|
267
|
-
)
|
239
|
+
console.print("1. Run uv `analysis.py` to perform data analysis and visualization")
|
268
240
|
console.print("2. The dataset is available in the mount-point directory:")
|
269
241
|
console.print(" - mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv")
|
270
|
-
console.print(
|
271
|
-
"On Windows platforms, please edit the fastagent.config.yaml and adjust the volume mount point."
|
272
|
-
)
|
242
|
+
console.print("On Windows platforms, please edit the fastagent.config.yaml and adjust the volume mount point.")
|
273
243
|
else:
|
274
244
|
console.print("\n[yellow]No files were created.[/yellow]")
|
275
245
|
|
276
246
|
|
277
247
|
@app.callback(invoke_without_command=True)
|
278
|
-
def main(ctx: typer.Context):
|
248
|
+
def main(ctx: typer.Context) -> None:
|
279
249
|
"""Create example applications and learn FastAgent patterns."""
|
280
250
|
if ctx.invoked_subcommand is None:
|
281
251
|
show_overview()
|
mcp_agent/cli/commands/config.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
+
from typing import NoReturn
|
2
|
+
|
1
3
|
import typer
|
2
4
|
|
3
5
|
app = typer.Typer()
|
4
6
|
|
5
7
|
|
6
8
|
@app.command()
|
7
|
-
def show():
|
9
|
+
def show() -> NoReturn:
|
8
10
|
"""Show the configuration."""
|
9
|
-
raise NotImplementedError(
|
10
|
-
"The show configuration command has not been implemented yet"
|
11
|
-
)
|
11
|
+
raise NotImplementedError("The show configuration command has not been implemented yet")
|
mcp_agent/cli/commands/setup.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
from pathlib import Path
|
2
|
+
|
2
3
|
import typer
|
3
|
-
from rich.prompt import Confirm
|
4
4
|
from rich.console import Console
|
5
|
+
from rich.prompt import Confirm
|
5
6
|
|
6
7
|
app = typer.Typer()
|
7
8
|
console = Console()
|
@@ -166,17 +167,13 @@ def init(
|
|
166
167
|
"-c",
|
167
168
|
help="Directory where configuration files will be created",
|
168
169
|
),
|
169
|
-
force: bool = typer.Option(
|
170
|
-
|
171
|
-
),
|
172
|
-
):
|
170
|
+
force: bool = typer.Option(False, "--force", "-f", help="Force overwrite existing files"),
|
171
|
+
) -> None:
|
173
172
|
"""Initialize a new FastAgent project with configuration files and example agent."""
|
174
173
|
|
175
174
|
config_path = Path(config_dir).resolve()
|
176
175
|
if not config_path.exists():
|
177
|
-
should_create = Confirm.ask(
|
178
|
-
f"Directory {config_path} does not exist. Create it?", default=True
|
179
|
-
)
|
176
|
+
should_create = Confirm.ask(f"Directory {config_path} does not exist. Create it?", default=True)
|
180
177
|
if should_create:
|
181
178
|
config_path.mkdir(parents=True)
|
182
179
|
else:
|
@@ -198,38 +195,26 @@ def init(
|
|
198
195
|
|
199
196
|
# Create configuration files
|
200
197
|
created = []
|
201
|
-
if create_file(
|
202
|
-
config_path / "fastagent.config.yaml", FASTAGENT_CONFIG_TEMPLATE, force
|
203
|
-
):
|
198
|
+
if create_file(config_path / "fastagent.config.yaml", FASTAGENT_CONFIG_TEMPLATE, force):
|
204
199
|
created.append("fastagent.yaml")
|
205
200
|
|
206
|
-
if create_file(
|
207
|
-
config_path / "fastagent.secrets.yaml", FASTAGENT_SECRETS_TEMPLATE, force
|
208
|
-
):
|
201
|
+
if create_file(config_path / "fastagent.secrets.yaml", FASTAGENT_SECRETS_TEMPLATE, force):
|
209
202
|
created.append("fastagent.secrets.yaml")
|
210
203
|
|
211
204
|
if create_file(config_path / "agent.py", AGENT_EXAMPLE_TEMPLATE, force):
|
212
205
|
created.append("agent.py")
|
213
206
|
|
214
207
|
# Only create .gitignore if none exists in parent directories
|
215
|
-
if needs_gitignore and create_file(
|
216
|
-
config_path / ".gitignore", GITIGNORE_TEMPLATE, force
|
217
|
-
):
|
208
|
+
if needs_gitignore and create_file(config_path / ".gitignore", GITIGNORE_TEMPLATE, force):
|
218
209
|
created.append(".gitignore")
|
219
210
|
|
220
211
|
if created:
|
221
212
|
console.print("\n[green]Setup completed successfully![/green]")
|
222
213
|
if "fastagent.secrets.yaml" in created:
|
223
214
|
console.print("\n[yellow]Important:[/yellow] Remember to:")
|
224
|
-
console.print(
|
225
|
-
|
226
|
-
)
|
227
|
-
console.print(
|
228
|
-
"2. Keep fastagent.secrets.yaml secure and never commit it to version control"
|
229
|
-
)
|
230
|
-
console.print(
|
231
|
-
"3. Update fastagent.config.yaml to set a default model (currently system default is 'haiku')"
|
232
|
-
)
|
215
|
+
console.print("1. Add your API keys to fastagent-secrets.yaml or set OPENAI_API_KEY and ANTHROPIC_API_KEY environment variables")
|
216
|
+
console.print("2. Keep fastagent.secrets.yaml secure and never commit it to version control")
|
217
|
+
console.print("3. Update fastagent.config.yaml to set a default model (currently system default is 'haiku')")
|
233
218
|
console.print("\nTo get started, run:")
|
234
219
|
console.print(" uv run agent.py")
|
235
220
|
else:
|
mcp_agent/cli/main.py
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
import typer
|
4
4
|
from rich.console import Console
|
5
5
|
from rich.table import Table
|
6
|
+
|
7
|
+
from mcp_agent.cli.commands import bootstrap, setup
|
6
8
|
from mcp_agent.cli.terminal import Application
|
7
|
-
from mcp_agent.cli.commands import setup, bootstrap
|
8
9
|
|
9
10
|
app = typer.Typer(
|
10
11
|
help="MCP Agent CLI - Build effective agents using Model Context Protocol",
|
@@ -20,7 +21,7 @@ application = Application()
|
|
20
21
|
console = Console()
|
21
22
|
|
22
23
|
|
23
|
-
def show_welcome():
|
24
|
+
def show_welcome() -> None:
|
24
25
|
"""Show a welcome message with available commands."""
|
25
26
|
from importlib.metadata import version
|
26
27
|
|
@@ -38,9 +39,7 @@ def show_welcome():
|
|
38
39
|
table.add_column("Description")
|
39
40
|
|
40
41
|
table.add_row("setup", "Set up a new agent project with configuration files")
|
41
|
-
table.add_row(
|
42
|
-
"bootstrap", "Create example applications (workflow, researcher, etc.)"
|
43
|
-
)
|
42
|
+
table.add_row("bootstrap", "Create example applications (workflow, researcher, etc.)")
|
44
43
|
# table.add_row("config", "Manage agent configuration settings")
|
45
44
|
|
46
45
|
console.print(table)
|
@@ -62,10 +61,8 @@ def main(
|
|
62
61
|
ctx: typer.Context,
|
63
62
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose mode"),
|
64
63
|
quiet: bool = typer.Option(False, "--quiet", "-q", help="Disable output"),
|
65
|
-
color: bool = typer.Option(
|
66
|
-
|
67
|
-
),
|
68
|
-
):
|
64
|
+
color: bool = typer.Option(True, "--color/--no-color", help="Enable/disable color output"),
|
65
|
+
) -> None:
|
69
66
|
"""FastAgent CLI - Build effective agents using Model Context Protocol (MCP).
|
70
67
|
|
71
68
|
Use --help with any command for detailed usage information.
|
mcp_agent/cli/terminal.py
CHANGED
@@ -2,7 +2,7 @@ from mcp_agent.console import console, error_console
|
|
2
2
|
|
3
3
|
|
4
4
|
class Application:
|
5
|
-
def __init__(self, verbosity: int = 0, enable_color: bool = True):
|
5
|
+
def __init__(self, verbosity: int = 0, enable_color: bool = True) -> None:
|
6
6
|
self.verbosity = verbosity
|
7
7
|
# Use the central console instances, respecting color setting
|
8
8
|
if not enable_color:
|
@@ -13,7 +13,7 @@ class Application:
|
|
13
13
|
self.console = console
|
14
14
|
self.error_console = error_console
|
15
15
|
|
16
|
-
def log(self, message: str, level: str = "info"):
|
16
|
+
def log(self, message: str, level: str = "info") -> None:
|
17
17
|
if level == "info" or (level == "debug" and self.verbosity > 0):
|
18
18
|
if level == "error":
|
19
19
|
self.error_console.print(f"[{level.upper()}] {message}")
|
mcp_agent/config.py
CHANGED
@@ -295,11 +295,7 @@ def get_settings(config_path: str | None = None) -> Settings:
|
|
295
295
|
"""Recursively merge two dictionaries, preserving nested structures."""
|
296
296
|
merged = base.copy()
|
297
297
|
for key, value in update.items():
|
298
|
-
if (
|
299
|
-
key in merged
|
300
|
-
and isinstance(merged[key], dict)
|
301
|
-
and isinstance(value, dict)
|
302
|
-
):
|
298
|
+
if key in merged and isinstance(merged[key], dict) and isinstance(value, dict):
|
303
299
|
merged[key] = deep_merge(merged[key], value)
|
304
300
|
else:
|
305
301
|
merged[key] = value
|
mcp_agent/context.py
CHANGED
@@ -4,41 +4,33 @@ A central context object to store global state that is shared across the applica
|
|
4
4
|
|
5
5
|
import asyncio
|
6
6
|
import concurrent.futures
|
7
|
-
from typing import Any, Optional, Union
|
8
|
-
|
9
|
-
from pydantic import BaseModel, ConfigDict
|
7
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
10
8
|
|
11
9
|
from mcp import ServerSession
|
12
|
-
|
13
10
|
from opentelemetry import trace
|
11
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
14
12
|
from opentelemetry.propagate import set_global_textmap
|
15
13
|
from opentelemetry.sdk.resources import Resource
|
16
14
|
from opentelemetry.sdk.trace import TracerProvider
|
17
15
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
|
18
16
|
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
19
|
-
from
|
17
|
+
from pydantic import BaseModel, ConfigDict
|
20
18
|
|
21
|
-
from mcp_agent.config import get_settings
|
22
|
-
from mcp_agent.config import Settings
|
23
|
-
from mcp_agent.executor.executor import Executor
|
19
|
+
from mcp_agent.config import Settings, get_settings
|
24
20
|
from mcp_agent.executor.decorator_registry import (
|
25
21
|
DecoratorRegistry,
|
26
22
|
register_asyncio_decorators,
|
27
23
|
)
|
24
|
+
from mcp_agent.executor.executor import AsyncioExecutor, Executor
|
28
25
|
from mcp_agent.executor.task_registry import ActivityRegistry
|
29
|
-
from mcp_agent.executor.executor import AsyncioExecutor
|
30
|
-
|
31
26
|
from mcp_agent.logging.events import EventFilter
|
32
|
-
from mcp_agent.logging.logger import LoggingConfig
|
27
|
+
from mcp_agent.logging.logger import LoggingConfig, get_logger
|
33
28
|
from mcp_agent.logging.transport import create_transport
|
34
29
|
from mcp_agent.mcp_server_registry import ServerRegistry
|
35
|
-
from mcp_agent.workflows.llm.llm_selector import ModelSelector
|
36
|
-
from mcp_agent.logging.logger import get_logger
|
37
|
-
|
38
30
|
|
39
31
|
if TYPE_CHECKING:
|
40
|
-
from mcp_agent.human_input.types import HumanInputCallback
|
41
32
|
from mcp_agent.executor.workflow_signal import SignalWaitCallback
|
33
|
+
from mcp_agent.human_input.types import HumanInputCallback
|
42
34
|
else:
|
43
35
|
# Runtime placeholders for the types
|
44
36
|
HumanInputCallback = Any
|
@@ -58,7 +50,6 @@ class Context(BaseModel):
|
|
58
50
|
human_input_handler: Optional[HumanInputCallback] = None
|
59
51
|
signal_notification: Optional[SignalWaitCallback] = None
|
60
52
|
upstream_session: Optional[ServerSession] = None # TODO: saqadri - figure this out
|
61
|
-
model_selector: Optional[ModelSelector] = None
|
62
53
|
|
63
54
|
# Registries
|
64
55
|
server_registry: Optional[ServerRegistry] = None
|
@@ -73,7 +64,7 @@ class Context(BaseModel):
|
|
73
64
|
)
|
74
65
|
|
75
66
|
|
76
|
-
async def configure_otel(config: "Settings"):
|
67
|
+
async def configure_otel(config: "Settings") -> None:
|
77
68
|
"""
|
78
69
|
Configure OpenTelemetry based on the application config.
|
79
70
|
"""
|
@@ -114,9 +105,7 @@ async def configure_otel(config: "Settings"):
|
|
114
105
|
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))
|
115
106
|
|
116
107
|
if config.otel.console_debug:
|
117
|
-
tracer_provider.add_span_processor(
|
118
|
-
BatchSpanProcessor(ConsoleSpanExporter())
|
119
|
-
)
|
108
|
+
tracer_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
|
120
109
|
else:
|
121
110
|
# Default to console exporter in development
|
122
111
|
tracer_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
|
@@ -125,7 +114,7 @@ async def configure_otel(config: "Settings"):
|
|
125
114
|
trace.set_tracer_provider(tracer_provider)
|
126
115
|
|
127
116
|
|
128
|
-
async def configure_logger(config: "Settings"):
|
117
|
+
async def configure_logger(config: "Settings") -> None:
|
129
118
|
"""
|
130
119
|
Configure logging and tracing based on the application config.
|
131
120
|
"""
|
@@ -141,7 +130,7 @@ async def configure_logger(config: "Settings"):
|
|
141
130
|
)
|
142
131
|
|
143
132
|
|
144
|
-
async def configure_usage_telemetry(_config: "Settings"):
|
133
|
+
async def configure_usage_telemetry(_config: "Settings") -> None:
|
145
134
|
"""
|
146
135
|
Configure usage telemetry based on the application config.
|
147
136
|
TODO: saqadri - implement usage tracking
|
@@ -167,9 +156,7 @@ async def configure_executor(config: "Settings"):
|
|
167
156
|
return executor
|
168
157
|
|
169
158
|
|
170
|
-
async def initialize_context(
|
171
|
-
config: Optional[Union["Settings", str]] = None, store_globally: bool = False
|
172
|
-
):
|
159
|
+
async def initialize_context(config: Optional[Union["Settings", str]] = None, store_globally: bool = False):
|
173
160
|
"""
|
174
161
|
Initialize the global application context.
|
175
162
|
"""
|
@@ -204,7 +191,7 @@ async def initialize_context(
|
|
204
191
|
return context
|
205
192
|
|
206
193
|
|
207
|
-
async def cleanup_context():
|
194
|
+
async def cleanup_context() -> None:
|
208
195
|
"""
|
209
196
|
Cleanup the global application context.
|
210
197
|
"""
|
mcp_agent/context_dependent.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
from contextlib import contextmanager
|
2
|
-
from typing import
|
3
|
-
|
2
|
+
from typing import TYPE_CHECKING, Any, Optional
|
4
3
|
|
5
4
|
if TYPE_CHECKING:
|
6
5
|
from mcp_agent.context import Context
|
@@ -12,7 +11,7 @@ class ContextDependent:
|
|
12
11
|
Provides both global fallback and instance-specific context support.
|
13
12
|
"""
|
14
13
|
|
15
|
-
def __init__(self, context: Optional["Context"] = None, **kwargs):
|
14
|
+
def __init__(self, context: Optional["Context"] = None, **kwargs: dict[str, Any]) -> None:
|
16
15
|
self._context = context
|
17
16
|
super().__init__(**kwargs)
|
18
17
|
|
@@ -32,10 +31,7 @@ class ContextDependent:
|
|
32
31
|
|
33
32
|
return get_current_context()
|
34
33
|
except Exception as e:
|
35
|
-
raise RuntimeError(
|
36
|
-
f"No context available for {self.__class__.__name__}. "
|
37
|
-
"Either initialize MCPApp first or pass context explicitly."
|
38
|
-
) from e
|
34
|
+
raise RuntimeError(f"No context available for {self.__class__.__name__}. Either initialize MCPApp first or pass context explicitly.") from e
|
39
35
|
|
40
36
|
@contextmanager
|
41
37
|
def use_context(self, context: "Context"):
|