fast-agent-mcp 0.1.12__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.
Files changed (126) hide show
  1. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/METADATA +1 -1
  2. fast_agent_mcp-0.1.13.dist-info/RECORD +164 -0
  3. mcp_agent/agents/agent.py +37 -79
  4. mcp_agent/app.py +16 -22
  5. mcp_agent/cli/commands/bootstrap.py +22 -52
  6. mcp_agent/cli/commands/config.py +4 -4
  7. mcp_agent/cli/commands/setup.py +11 -26
  8. mcp_agent/cli/main.py +6 -9
  9. mcp_agent/cli/terminal.py +2 -2
  10. mcp_agent/config.py +1 -5
  11. mcp_agent/context.py +13 -24
  12. mcp_agent/context_dependent.py +3 -7
  13. mcp_agent/core/agent_app.py +45 -121
  14. mcp_agent/core/agent_utils.py +3 -5
  15. mcp_agent/core/decorators.py +5 -12
  16. mcp_agent/core/enhanced_prompt.py +25 -52
  17. mcp_agent/core/exceptions.py +8 -8
  18. mcp_agent/core/factory.py +29 -70
  19. mcp_agent/core/fastagent.py +48 -88
  20. mcp_agent/core/mcp_content.py +8 -16
  21. mcp_agent/core/prompt.py +8 -15
  22. mcp_agent/core/proxies.py +34 -25
  23. mcp_agent/core/request_params.py +6 -3
  24. mcp_agent/core/types.py +4 -6
  25. mcp_agent/core/validation.py +4 -3
  26. mcp_agent/executor/decorator_registry.py +11 -23
  27. mcp_agent/executor/executor.py +8 -17
  28. mcp_agent/executor/task_registry.py +2 -4
  29. mcp_agent/executor/temporal.py +28 -74
  30. mcp_agent/executor/workflow.py +3 -5
  31. mcp_agent/executor/workflow_signal.py +17 -29
  32. mcp_agent/human_input/handler.py +4 -9
  33. mcp_agent/human_input/types.py +2 -3
  34. mcp_agent/logging/events.py +1 -5
  35. mcp_agent/logging/json_serializer.py +7 -6
  36. mcp_agent/logging/listeners.py +20 -23
  37. mcp_agent/logging/logger.py +15 -17
  38. mcp_agent/logging/rich_progress.py +10 -8
  39. mcp_agent/logging/tracing.py +4 -6
  40. mcp_agent/logging/transport.py +22 -22
  41. mcp_agent/mcp/gen_client.py +4 -12
  42. mcp_agent/mcp/interfaces.py +71 -86
  43. mcp_agent/mcp/mcp_agent_client_session.py +11 -19
  44. mcp_agent/mcp/mcp_agent_server.py +8 -10
  45. mcp_agent/mcp/mcp_aggregator.py +45 -117
  46. mcp_agent/mcp/mcp_connection_manager.py +16 -37
  47. mcp_agent/mcp/prompt_message_multipart.py +12 -18
  48. mcp_agent/mcp/prompt_serialization.py +13 -38
  49. mcp_agent/mcp/prompts/prompt_load.py +99 -0
  50. mcp_agent/mcp/prompts/prompt_server.py +21 -128
  51. mcp_agent/mcp/prompts/prompt_template.py +20 -42
  52. mcp_agent/mcp/resource_utils.py +8 -17
  53. mcp_agent/mcp/sampling.py +5 -14
  54. mcp_agent/mcp/stdio.py +11 -8
  55. mcp_agent/mcp_server/agent_server.py +10 -17
  56. mcp_agent/mcp_server_registry.py +13 -35
  57. mcp_agent/resources/examples/data-analysis/analysis-campaign.py +1 -1
  58. mcp_agent/resources/examples/data-analysis/analysis.py +1 -1
  59. mcp_agent/resources/examples/data-analysis/slides.py +110 -0
  60. mcp_agent/resources/examples/internal/agent.py +2 -1
  61. mcp_agent/resources/examples/internal/job.py +2 -1
  62. mcp_agent/resources/examples/internal/prompt_category.py +1 -1
  63. mcp_agent/resources/examples/internal/prompt_sizing.py +3 -5
  64. mcp_agent/resources/examples/internal/sizer.py +2 -1
  65. mcp_agent/resources/examples/internal/social.py +2 -1
  66. mcp_agent/resources/examples/mcp_researcher/researcher-eval.py +1 -1
  67. mcp_agent/resources/examples/prompting/agent.py +2 -1
  68. mcp_agent/resources/examples/prompting/image_server.py +5 -11
  69. mcp_agent/resources/examples/researcher/researcher-eval.py +1 -1
  70. mcp_agent/resources/examples/researcher/researcher-imp.py +3 -4
  71. mcp_agent/resources/examples/researcher/researcher.py +2 -1
  72. mcp_agent/resources/examples/workflows/agent_build.py +2 -1
  73. mcp_agent/resources/examples/workflows/chaining.py +2 -1
  74. mcp_agent/resources/examples/workflows/evaluator.py +2 -1
  75. mcp_agent/resources/examples/workflows/human_input.py +2 -1
  76. mcp_agent/resources/examples/workflows/orchestrator.py +2 -1
  77. mcp_agent/resources/examples/workflows/parallel.py +2 -1
  78. mcp_agent/resources/examples/workflows/router.py +2 -1
  79. mcp_agent/resources/examples/workflows/sse.py +1 -1
  80. mcp_agent/telemetry/usage_tracking.py +2 -1
  81. mcp_agent/ui/console_display.py +15 -39
  82. mcp_agent/workflows/embedding/embedding_base.py +1 -4
  83. mcp_agent/workflows/embedding/embedding_cohere.py +2 -2
  84. mcp_agent/workflows/embedding/embedding_openai.py +4 -13
  85. mcp_agent/workflows/evaluator_optimizer/evaluator_optimizer.py +23 -57
  86. mcp_agent/workflows/intent_classifier/intent_classifier_base.py +5 -8
  87. mcp_agent/workflows/intent_classifier/intent_classifier_embedding.py +7 -11
  88. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_cohere.py +4 -8
  89. mcp_agent/workflows/intent_classifier/intent_classifier_embedding_openai.py +4 -8
  90. mcp_agent/workflows/intent_classifier/intent_classifier_llm.py +11 -22
  91. mcp_agent/workflows/intent_classifier/intent_classifier_llm_anthropic.py +3 -3
  92. mcp_agent/workflows/intent_classifier/intent_classifier_llm_openai.py +4 -6
  93. mcp_agent/workflows/llm/anthropic_utils.py +8 -29
  94. mcp_agent/workflows/llm/augmented_llm.py +69 -247
  95. mcp_agent/workflows/llm/augmented_llm_anthropic.py +39 -73
  96. mcp_agent/workflows/llm/augmented_llm_openai.py +42 -97
  97. mcp_agent/workflows/llm/augmented_llm_passthrough.py +13 -20
  98. mcp_agent/workflows/llm/augmented_llm_playback.py +8 -6
  99. mcp_agent/workflows/llm/memory.py +103 -0
  100. mcp_agent/workflows/llm/model_factory.py +8 -20
  101. mcp_agent/workflows/llm/openai_utils.py +1 -1
  102. mcp_agent/workflows/llm/prompt_utils.py +1 -3
  103. mcp_agent/workflows/llm/providers/multipart_converter_anthropic.py +47 -89
  104. mcp_agent/workflows/llm/providers/multipart_converter_openai.py +20 -55
  105. mcp_agent/workflows/llm/providers/openai_multipart.py +19 -61
  106. mcp_agent/workflows/llm/providers/sampling_converter_anthropic.py +10 -12
  107. mcp_agent/workflows/llm/providers/sampling_converter_openai.py +7 -11
  108. mcp_agent/workflows/llm/sampling_converter.py +4 -11
  109. mcp_agent/workflows/llm/sampling_format_converter.py +12 -12
  110. mcp_agent/workflows/orchestrator/orchestrator.py +24 -67
  111. mcp_agent/workflows/orchestrator/orchestrator_models.py +14 -40
  112. mcp_agent/workflows/parallel/fan_in.py +17 -47
  113. mcp_agent/workflows/parallel/fan_out.py +6 -12
  114. mcp_agent/workflows/parallel/parallel_llm.py +9 -26
  115. mcp_agent/workflows/router/router_base.py +19 -49
  116. mcp_agent/workflows/router/router_embedding.py +11 -25
  117. mcp_agent/workflows/router/router_embedding_cohere.py +2 -2
  118. mcp_agent/workflows/router/router_embedding_openai.py +2 -2
  119. mcp_agent/workflows/router/router_llm.py +12 -28
  120. mcp_agent/workflows/swarm/swarm.py +20 -48
  121. mcp_agent/workflows/swarm/swarm_anthropic.py +2 -2
  122. mcp_agent/workflows/swarm/swarm_openai.py +2 -2
  123. fast_agent_mcp-0.1.12.dist-info/RECORD +0 -161
  124. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/WHEEL +0 -0
  125. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/entry_points.txt +0 -0
  126. {fast_agent_mcp-0.1.12.dist-info → fast_agent_mcp-0.1.13.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  import asyncio
2
2
  import uuid
3
- from abc import abstractmethod, ABC
3
+ from abc import ABC, abstractmethod
4
4
  from typing import Any, Callable, Dict, Generic, List, Protocol, TypeVar
5
5
 
6
6
  from pydantic import BaseModel, ConfigDict
@@ -71,14 +71,14 @@ class PendingSignal(BaseModel):
71
71
  class BaseSignalHandler(ABC, Generic[SignalValueT]):
72
72
  """Base class implementing common signal handling functionality."""
73
73
 
74
- def __init__(self):
74
+ def __init__(self) -> None:
75
75
  # Map signal_name -> list of PendingSignal objects
76
76
  self._pending_signals: Dict[str, List[PendingSignal]] = {}
77
77
  # Map signal_name -> list of (unique_name, handler) tuples
78
78
  self._handlers: Dict[str, List[tuple[str, Callable]]] = {}
79
79
  self._lock = asyncio.Lock()
80
80
 
81
- async def cleanup(self, signal_name: str | None = None):
81
+ async def cleanup(self, signal_name: str | None = None) -> None:
82
82
  """Clean up handlers and registrations for a signal or all signals."""
83
83
  async with self._lock:
84
84
  if signal_name:
@@ -90,7 +90,7 @@ class BaseSignalHandler(ABC, Generic[SignalValueT]):
90
90
  self._handlers.clear()
91
91
  self._pending_signals.clear()
92
92
 
93
- def validate_signal(self, signal: Signal[SignalValueT]):
93
+ def validate_signal(self, signal: Signal[SignalValueT]) -> None:
94
94
  """Validate signal properties."""
95
95
  if not signal.name:
96
96
  raise ValueError("Signal name is required")
@@ -102,7 +102,7 @@ class BaseSignalHandler(ABC, Generic[SignalValueT]):
102
102
  def decorator(func: Callable) -> Callable:
103
103
  unique_name = f"{signal_name}_{uuid.uuid4()}"
104
104
 
105
- async def wrapped(value: SignalValueT):
105
+ async def wrapped(value: SignalValueT) -> None:
106
106
  try:
107
107
  if asyncio.iscoroutinefunction(func):
108
108
  await func(value)
@@ -133,7 +133,7 @@ class BaseSignalHandler(ABC, Generic[SignalValueT]):
133
133
  class ConsoleSignalHandler(SignalHandler[str]):
134
134
  """Simple console-based signal handling (blocks on input)."""
135
135
 
136
- def __init__(self):
136
+ def __init__(self) -> None:
137
137
  self._pending_signals: Dict[str, List[PendingSignal]] = {}
138
138
  self._handlers: Dict[str, List[Callable]] = {}
139
139
 
@@ -147,9 +147,7 @@ class ConsoleSignalHandler(SignalHandler[str]):
147
147
  loop = asyncio.get_event_loop()
148
148
  if timeout_seconds is not None:
149
149
  try:
150
- value = await asyncio.wait_for(
151
- loop.run_in_executor(None, input, "Enter value: "), timeout_seconds
152
- )
150
+ value = await asyncio.wait_for(loop.run_in_executor(None, input, "Enter value: "), timeout_seconds)
153
151
  except asyncio.TimeoutError:
154
152
  print("\nTimeout waiting for input")
155
153
  raise
@@ -163,7 +161,7 @@ class ConsoleSignalHandler(SignalHandler[str]):
163
161
 
164
162
  def on_signal(self, signal_name):
165
163
  def decorator(func):
166
- async def wrapped(value: SignalValueT):
164
+ async def wrapped(value: SignalValueT) -> None:
167
165
  if asyncio.iscoroutinefunction(func):
168
166
  await func(value)
169
167
  else:
@@ -174,13 +172,11 @@ class ConsoleSignalHandler(SignalHandler[str]):
174
172
 
175
173
  return decorator
176
174
 
177
- async def signal(self, signal):
175
+ async def signal(self, signal) -> None:
178
176
  print(f"[SIGNAL SENT: {signal.name}] Value: {signal.payload}")
179
177
 
180
178
  handlers = self._handlers.get(signal.name, [])
181
- await asyncio.gather(
182
- *(handler(signal) for handler in handlers), return_exceptions=True
183
- )
179
+ await asyncio.gather(*(handler(signal) for handler in handlers), return_exceptions=True)
184
180
 
185
181
  # Notify any waiting coroutines
186
182
  if signal.name in self._pending_signals:
@@ -194,9 +190,7 @@ class AsyncioSignalHandler(BaseSignalHandler[SignalValueT]):
194
190
  Asyncio-based signal handling using an internal dictionary of asyncio Events.
195
191
  """
196
192
 
197
- async def wait_for_signal(
198
- self, signal, timeout_seconds: int | None = None
199
- ) -> SignalValueT:
193
+ async def wait_for_signal(self, signal, timeout_seconds: int | None = None) -> SignalValueT:
200
194
  event = asyncio.Event()
201
195
  unique_name = str(uuid.uuid4())
202
196
 
@@ -226,17 +220,13 @@ class AsyncioSignalHandler(BaseSignalHandler[SignalValueT]):
226
220
  async with self._lock:
227
221
  # Remove from pending signals
228
222
  if signal.name in self._pending_signals:
229
- self._pending_signals[signal.name] = [
230
- ps
231
- for ps in self._pending_signals[signal.name]
232
- if ps.registration.unique_name != unique_name
233
- ]
223
+ self._pending_signals[signal.name] = [ps for ps in self._pending_signals[signal.name] if ps.registration.unique_name != unique_name]
234
224
  if not self._pending_signals[signal.name]:
235
225
  del self._pending_signals[signal.name]
236
226
 
237
227
  def on_signal(self, signal_name):
238
228
  def decorator(func):
239
- async def wrapped(value: SignalValueT):
229
+ async def wrapped(value: SignalValueT) -> None:
240
230
  if asyncio.iscoroutinefunction(func):
241
231
  await func(value)
242
232
  else:
@@ -247,7 +237,7 @@ class AsyncioSignalHandler(BaseSignalHandler[SignalValueT]):
247
237
 
248
238
  return decorator
249
239
 
250
- async def signal(self, signal):
240
+ async def signal(self, signal) -> None:
251
241
  async with self._lock:
252
242
  # Notify any waiting coroutines
253
243
  if signal.name in self._pending_signals:
@@ -272,11 +262,11 @@ class LocalSignalStore:
272
262
  and triggers them when a signal is emitted.
273
263
  """
274
264
 
275
- def __init__(self):
265
+ def __init__(self) -> None:
276
266
  # For each signal_name, store a list of futures that are waiting for it
277
267
  self._waiters: Dict[str, List[asyncio.Future]] = {}
278
268
 
279
- async def emit(self, signal_name: str, payload: Any):
269
+ async def emit(self, signal_name: str, payload: Any) -> None:
280
270
  # If we have waiting futures, set their result
281
271
  if signal_name in self._waiters:
282
272
  for future in self._waiters[signal_name]:
@@ -284,9 +274,7 @@ class LocalSignalStore:
284
274
  future.set_result(payload)
285
275
  self._waiters[signal_name].clear()
286
276
 
287
- async def wait_for(
288
- self, signal_name: str, timeout_seconds: int | None = None
289
- ) -> Any:
277
+ async def wait_for(self, signal_name: str, timeout_seconds: int | None = None) -> Any:
290
278
  loop = asyncio.get_running_loop()
291
279
  future = loop.create_future()
292
280
 
@@ -1,13 +1,14 @@
1
1
  import asyncio
2
+
2
3
  from rich.panel import Panel
3
4
 
4
5
  from mcp_agent.console import console
6
+ from mcp_agent.core.enhanced_prompt import get_enhanced_input, handle_special_commands
5
7
  from mcp_agent.human_input.types import (
6
8
  HumanInputRequest,
7
9
  HumanInputResponse,
8
10
  )
9
11
  from mcp_agent.progress_display import progress_display
10
- from mcp_agent.core.enhanced_prompt import get_enhanced_input, handle_special_commands
11
12
 
12
13
 
13
14
  async def console_input_callback(request: HumanInputRequest) -> HumanInputResponse:
@@ -29,11 +30,7 @@ async def console_input_callback(request: HumanInputRequest) -> HumanInputRespon
29
30
  )
30
31
 
31
32
  # Extract agent name from metadata dictionary
32
- agent_name = (
33
- request.metadata.get("agent_name", "Unknown Agent")
34
- if request.metadata
35
- else "Unknown Agent"
36
- )
33
+ agent_name = request.metadata.get("agent_name", "Unknown Agent") if request.metadata else "Unknown Agent"
37
34
 
38
35
  # Use the context manager to pause the progress display while getting input
39
36
  with progress_display.paused():
@@ -70,9 +67,7 @@ async def console_input_callback(request: HumanInputRequest) -> HumanInputRespon
70
67
  if isinstance(command_result, dict) and "list_prompts" in command_result:
71
68
  from rich import print as rich_print
72
69
 
73
- rich_print(
74
- "[yellow]Prompt listing not available in human input context[/yellow]"
75
- )
70
+ rich_print("[yellow]Prompt listing not available in human input context[/yellow]")
76
71
 
77
72
  except KeyboardInterrupt:
78
73
  console.print("\n[yellow]Input interrupted[/yellow]")
@@ -1,4 +1,5 @@
1
1
  from typing import Any, AsyncIterator, Protocol
2
+
2
3
  from pydantic import BaseModel
3
4
 
4
5
  HUMAN_INPUT_SIGNAL_NAME = "__human_input__"
@@ -42,9 +43,7 @@ class HumanInputResponse(BaseModel):
42
43
  class HumanInputCallback(Protocol):
43
44
  """Protocol for callbacks that handle human input requests."""
44
45
 
45
- async def __call__(
46
- self, request: HumanInputRequest
47
- ) -> AsyncIterator[HumanInputResponse]:
46
+ async def __call__(self, request: HumanInputRequest) -> AsyncIterator[HumanInputResponse]:
48
47
  """
49
48
  Handle a human input request.
50
49
 
@@ -4,7 +4,6 @@ Events and event filters for the logger module for the MCP Agent
4
4
 
5
5
  import logging
6
6
  import random
7
-
8
7
  from datetime import datetime
9
8
  from typing import (
10
9
  Any,
@@ -15,7 +14,6 @@ from typing import (
15
14
 
16
15
  from pydantic import BaseModel, ConfigDict, Field
17
16
 
18
-
19
17
  EventType = Literal["debug", "info", "warning", "error", "progress"]
20
18
  """Broad categories for events (severity or role)."""
21
19
 
@@ -86,9 +84,7 @@ class EventFilter(BaseModel):
86
84
  return False
87
85
 
88
86
  # 3) Filter by namespace prefix
89
- if self.namespaces and not any(
90
- event.namespace.startswith(ns) for ns in self.namespaces
91
- ):
87
+ if self.namespaces and not any(event.namespace.startswith(ns) for ns in self.namespaces):
92
88
  return False
93
89
 
94
90
  # 4) Minimum severity
@@ -1,13 +1,14 @@
1
+ import dataclasses
2
+ import inspect
1
3
  import os
2
4
  import warnings
3
- from typing import Any, Dict, Iterable, Set
4
- from datetime import datetime, date
5
+ from datetime import date, datetime
5
6
  from decimal import Decimal
7
+ from enum import Enum
6
8
  from pathlib import Path
9
+ from typing import Any, Dict, Iterable, Set
7
10
  from uuid import UUID
8
- from enum import Enum
9
- import dataclasses
10
- import inspect
11
+
11
12
  import httpx
12
13
 
13
14
  from mcp_agent.logging import logger
@@ -34,7 +35,7 @@ class JSONSerializer:
34
35
  "refresh_token",
35
36
  }
36
37
 
37
- def __init__(self):
38
+ def __init__(self) -> None:
38
39
  # Set of already processed objects to prevent infinite recursion
39
40
  self._processed_objects: Set[int] = set()
40
41
  # Check if secrets should be logged in full
@@ -5,12 +5,11 @@ Listeners for the logger module of MCP Agent.
5
5
  import asyncio
6
6
  import logging
7
7
  import time
8
-
9
8
  from abc import ABC, abstractmethod
10
9
  from typing import Dict, List
11
10
 
12
- from mcp_agent.logging.events import Event, EventFilter, EventType
13
11
  from mcp_agent.event_progress import convert_log_event
12
+ from mcp_agent.logging.events import Event, EventFilter, EventType
14
13
 
15
14
 
16
15
  class EventListener(ABC):
@@ -27,11 +26,11 @@ class LifecycleAwareListener(EventListener):
27
26
  The event bus calls these at bus start/stop time.
28
27
  """
29
28
 
30
- async def start(self):
29
+ async def start(self) -> None:
31
30
  """Start an event listener, usually when the event bus is set up."""
32
31
  pass
33
32
 
34
- async def stop(self):
33
+ async def stop(self) -> None:
35
34
  """Stop an event listener, usually when the event bus is shutting down."""
36
35
  pass
37
36
 
@@ -42,7 +41,7 @@ class FilteredListener(LifecycleAwareListener):
42
41
  Subclasses override _handle_matched_event().
43
42
  """
44
43
 
45
- def __init__(self, event_filter: EventFilter | None = None):
44
+ def __init__(self, event_filter: EventFilter | None = None) -> None:
46
45
  """
47
46
  Initialize the listener.
48
47
  Args:
@@ -50,11 +49,11 @@ class FilteredListener(LifecycleAwareListener):
50
49
  """
51
50
  self.filter = event_filter
52
51
 
53
- async def handle_event(self, event):
52
+ async def handle_event(self, event) -> None:
54
53
  if not self.filter or self.filter.matches(event):
55
54
  await self.handle_matched_event(event)
56
55
 
57
- async def handle_matched_event(self, event: Event):
56
+ async def handle_matched_event(self, event: Event) -> None:
58
57
  """Process an event that matches the filter."""
59
58
  pass
60
59
 
@@ -68,7 +67,7 @@ class LoggingListener(FilteredListener):
68
67
  self,
69
68
  event_filter: EventFilter | None = None,
70
69
  logger: logging.Logger | None = None,
71
- ):
70
+ ) -> None:
72
71
  """
73
72
  Initialize the listener.
74
73
  Args:
@@ -77,7 +76,7 @@ class LoggingListener(FilteredListener):
77
76
  super().__init__(event_filter=event_filter)
78
77
  self.logger = logger or logging.getLogger("mcp_agent")
79
78
 
80
- async def handle_matched_event(self, event):
79
+ async def handle_matched_event(self, event) -> None:
81
80
  level_map: Dict[EventType, int] = {
82
81
  "debug": logging.DEBUG,
83
82
  "info": logging.INFO,
@@ -113,7 +112,7 @@ class ProgressListener(LifecycleAwareListener):
113
112
  FilteredListener, we get events before any filtering occurs.
114
113
  """
115
114
 
116
- def __init__(self, display=None):
115
+ def __init__(self, display=None) -> None:
117
116
  """Initialize the progress listener.
118
117
  Args:
119
118
  display: Optional display handler. If None, the shared progress_display will be used.
@@ -122,15 +121,15 @@ class ProgressListener(LifecycleAwareListener):
122
121
 
123
122
  self.display = display or progress_display
124
123
 
125
- async def start(self):
124
+ async def start(self) -> None:
126
125
  """Start the progress display."""
127
126
  self.display.start()
128
127
 
129
- async def stop(self):
128
+ async def stop(self) -> None:
130
129
  """Stop the progress display."""
131
130
  self.display.stop()
132
131
 
133
- async def handle_event(self, event: Event):
132
+ async def handle_event(self, event: Event) -> None:
134
133
  """Process an incoming event and display progress if relevant."""
135
134
 
136
135
  if event.data:
@@ -150,7 +149,7 @@ class BatchingListener(FilteredListener):
150
149
  event_filter: EventFilter | None = None,
151
150
  batch_size: int = 5,
152
151
  flush_interval: float = 2.0,
153
- ):
152
+ ) -> None:
154
153
  """
155
154
  Initialize the listener.
156
155
  Args:
@@ -165,12 +164,12 @@ class BatchingListener(FilteredListener):
165
164
  self._flush_task: asyncio.Task | None = None # Task for periodic flush loop
166
165
  self._stop_event = None # Event to signal flush task to stop
167
166
 
168
- async def start(self, loop=None):
167
+ async def start(self, loop=None) -> None:
169
168
  """Spawn a periodic flush loop."""
170
169
  self._stop_event = asyncio.Event()
171
170
  self._flush_task = asyncio.create_task(self._periodic_flush())
172
171
 
173
- async def stop(self):
172
+ async def stop(self) -> None:
174
173
  """Stop flush loop and flush any remaining events."""
175
174
  if self._stop_event:
176
175
  self._stop_event.set()
@@ -181,13 +180,11 @@ class BatchingListener(FilteredListener):
181
180
  self._flush_task = None
182
181
  await self.flush()
183
182
 
184
- async def _periodic_flush(self):
183
+ async def _periodic_flush(self) -> None:
185
184
  try:
186
185
  while not self._stop_event.is_set():
187
186
  try:
188
- await asyncio.wait_for(
189
- self._stop_event.wait(), timeout=self.flush_interval
190
- )
187
+ await asyncio.wait_for(self._stop_event.wait(), timeout=self.flush_interval)
191
188
  except asyncio.TimeoutError:
192
189
  await self.flush()
193
190
  # except asyncio.CancelledError:
@@ -195,12 +192,12 @@ class BatchingListener(FilteredListener):
195
192
  finally:
196
193
  await self.flush() # Final flush
197
194
 
198
- async def handle_matched_event(self, event):
195
+ async def handle_matched_event(self, event) -> None:
199
196
  self.batch.append(event)
200
197
  if len(self.batch) >= self.batch_size:
201
198
  await self.flush()
202
199
 
203
- async def flush(self):
200
+ async def flush(self) -> None:
204
201
  """Flush the current batch of events."""
205
202
  if not self.batch:
206
203
  return
@@ -209,5 +206,5 @@ class BatchingListener(FilteredListener):
209
206
  self.last_flush = time.time()
210
207
  await self._process_batch(to_process)
211
208
 
212
- async def _process_batch(self, events: List[Event]):
209
+ async def _process_batch(self, events: List[Event]) -> None:
213
210
  pass
@@ -10,10 +10,8 @@ Logger module for the MCP Agent, which provides:
10
10
  import asyncio
11
11
  import threading
12
12
  import time
13
-
14
- from typing import Any, Dict
15
-
16
13
  from contextlib import asynccontextmanager, contextmanager
14
+ from typing import Any, Dict
17
15
 
18
16
  from mcp_agent.logging.events import Event, EventContext, EventFilter, EventType
19
17
  from mcp_agent.logging.listeners import (
@@ -31,7 +29,7 @@ class Logger:
31
29
  - `name` can be a custom domain-specific event name, e.g. "ORDER_PLACED".
32
30
  """
33
31
 
34
- def __init__(self, namespace: str):
32
+ def __init__(self, namespace: str) -> None:
35
33
  self.namespace = namespace
36
34
  self.event_bus = AsyncEventBus.get()
37
35
 
@@ -45,7 +43,7 @@ class Logger:
45
43
  asyncio.set_event_loop(loop)
46
44
  return loop
47
45
 
48
- def _emit_event(self, event: Event):
46
+ def _emit_event(self, event: Event) -> None:
49
47
  """Emit an event by running it in the event loop."""
50
48
  loop = self._ensure_event_loop()
51
49
  if loop.is_running():
@@ -62,7 +60,7 @@ class Logger:
62
60
  message: str,
63
61
  context: EventContext | None,
64
62
  data: dict,
65
- ):
63
+ ) -> None:
66
64
  """Create and emit an event."""
67
65
  evt = Event(
68
66
  type=etype,
@@ -78,9 +76,9 @@ class Logger:
78
76
  self,
79
77
  message: str,
80
78
  name: str | None = None,
81
- context: EventContext = None,
79
+ context: EventContext | None = None,
82
80
  **data,
83
- ):
81
+ ) -> None:
84
82
  """Log a debug message."""
85
83
  self.event("debug", name, message, context, data)
86
84
 
@@ -88,9 +86,9 @@ class Logger:
88
86
  self,
89
87
  message: str,
90
88
  name: str | None = None,
91
- context: EventContext = None,
89
+ context: EventContext | None = None,
92
90
  **data,
93
- ):
91
+ ) -> None:
94
92
  """Log an info message."""
95
93
  self.event("info", name, message, context, data)
96
94
 
@@ -98,9 +96,9 @@ class Logger:
98
96
  self,
99
97
  message: str,
100
98
  name: str | None = None,
101
- context: EventContext = None,
99
+ context: EventContext | None = None,
102
100
  **data,
103
- ):
101
+ ) -> None:
104
102
  """Log a warning message."""
105
103
  self.event("warning", name, message, context, data)
106
104
 
@@ -108,9 +106,9 @@ class Logger:
108
106
  self,
109
107
  message: str,
110
108
  name: str | None = None,
111
- context: EventContext = None,
109
+ context: EventContext | None = None,
112
110
  **data,
113
- ):
111
+ ) -> None:
114
112
  """Log an error message."""
115
113
  self.event("error", name, message, context, data)
116
114
 
@@ -118,10 +116,10 @@ class Logger:
118
116
  self,
119
117
  message: str,
120
118
  name: str | None = None,
121
- percentage: float = None,
122
- context: EventContext = None,
119
+ percentage: float | None = None,
120
+ context: EventContext | None = None,
123
121
  **data,
124
- ):
122
+ ) -> None:
125
123
  """Log a progress message."""
126
124
  merged_data = dict(percentage=percentage, **data)
127
125
  self.event("progress", name, message, context, merged_data)
@@ -1,18 +1,20 @@
1
1
  """Rich-based progress display for MCP Agent."""
2
2
 
3
3
  import time
4
+ from contextlib import contextmanager
4
5
  from typing import Optional
6
+
5
7
  from rich.console import Console
6
- from mcp_agent.console import console as default_console
7
- from mcp_agent.event_progress import ProgressEvent, ProgressAction
8
8
  from rich.progress import Progress, SpinnerColumn, TextColumn
9
- from contextlib import contextmanager
9
+
10
+ from mcp_agent.console import console as default_console
11
+ from mcp_agent.event_progress import ProgressAction, ProgressEvent
10
12
 
11
13
 
12
14
  class RichProgressDisplay:
13
15
  """Rich-based display for progress events."""
14
16
 
15
- def __init__(self, console: Optional[Console] = None):
17
+ def __init__(self, console: Optional[Console] = None) -> None:
16
18
  """Initialize the progress display."""
17
19
  self.console = console or default_console
18
20
  self._taskmap = {}
@@ -29,16 +31,16 @@ class RichProgressDisplay:
29
31
  )
30
32
  self._paused = False
31
33
 
32
- def start(self):
34
+ def start(self) -> None:
33
35
  """start"""
34
36
 
35
37
  self._progress.start()
36
38
 
37
- def stop(self):
39
+ def stop(self) -> None:
38
40
  """stop"""
39
41
  self._progress.stop()
40
42
 
41
- def pause(self):
43
+ def pause(self) -> None:
42
44
  """Pause the progress display."""
43
45
  if not self._paused:
44
46
  self._paused = True
@@ -47,7 +49,7 @@ class RichProgressDisplay:
47
49
  task.visible = False
48
50
  self._progress.stop()
49
51
 
50
- def resume(self):
52
+ def resume(self) -> None:
51
53
  """Resume the progress display."""
52
54
  if self._paused:
53
55
  for task in self._progress.tasks:
@@ -5,16 +5,14 @@ for the Logger module for MCP Agent
5
5
 
6
6
  import asyncio
7
7
  import functools
8
- from typing import Any, Dict, Callable, Optional, Tuple, TYPE_CHECKING
8
+ from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple
9
9
 
10
10
  from opentelemetry import trace
11
11
  from opentelemetry.context import Context as OtelContext
12
12
  from opentelemetry.propagate import extract as otel_extract
13
- from opentelemetry.trace import set_span_in_context
13
+ from opentelemetry.trace import SpanKind, Status, StatusCode, set_span_in_context
14
14
  from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
15
15
 
16
- from opentelemetry.trace import SpanKind, Status, StatusCode
17
-
18
16
  from mcp_agent.context_dependent import ContextDependent
19
17
 
20
18
  if TYPE_CHECKING:
@@ -27,7 +25,7 @@ class TelemetryManager(ContextDependent):
27
25
  Decorator usage: @telemetry.traced("SomeSpanName")
28
26
  """
29
27
 
30
- def __init__(self, context: Optional["Context"] = None, **kwargs):
28
+ def __init__(self, context: Optional["Context"] = None, **kwargs) -> None:
31
29
  # If needed, configure resources, exporters, etc.
32
30
  # E.g.: from opentelemetry.sdk.trace import TracerProvider
33
31
  # trace.set_tracer_provider(TracerProvider(...))
@@ -88,7 +86,7 @@ class TelemetryManager(ContextDependent):
88
86
 
89
87
  return decorator
90
88
 
91
- def _record_args(self, span, args, kwargs):
89
+ def _record_args(self, span, args, kwargs) -> None:
92
90
  """Optionally record primitive args as span attributes."""
93
91
  for i, arg in enumerate(args):
94
92
  if isinstance(arg, (str, int, float, bool)):