fast-agent-mcp 0.2.4__py3-none-any.whl → 0.2.6__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 (33) hide show
  1. {fast_agent_mcp-0.2.4.dist-info → fast_agent_mcp-0.2.6.dist-info}/METADATA +2 -2
  2. {fast_agent_mcp-0.2.4.dist-info → fast_agent_mcp-0.2.6.dist-info}/RECORD +32 -33
  3. mcp_agent/agents/agent.py +1 -1
  4. mcp_agent/agents/base_agent.py +25 -13
  5. mcp_agent/agents/workflow/chain_agent.py +7 -1
  6. mcp_agent/agents/workflow/evaluator_optimizer.py +6 -0
  7. mcp_agent/agents/workflow/orchestrator_agent.py +6 -1
  8. mcp_agent/agents/workflow/parallel_agent.py +7 -1
  9. mcp_agent/agents/workflow/router_agent.py +7 -2
  10. mcp_agent/cli/commands/setup.py +2 -2
  11. mcp_agent/cli/main.py +11 -0
  12. mcp_agent/config.py +29 -7
  13. mcp_agent/context.py +2 -0
  14. mcp_agent/core/agent_app.py +8 -19
  15. mcp_agent/core/agent_types.py +1 -0
  16. mcp_agent/core/direct_decorators.py +2 -1
  17. mcp_agent/core/direct_factory.py +6 -15
  18. mcp_agent/core/enhanced_prompt.py +3 -3
  19. mcp_agent/core/fastagent.py +202 -46
  20. mcp_agent/core/interactive_prompt.py +1 -1
  21. mcp_agent/llm/augmented_llm.py +8 -10
  22. mcp_agent/llm/augmented_llm_passthrough.py +3 -1
  23. mcp_agent/llm/model_factory.py +5 -7
  24. mcp_agent/mcp/interfaces.py +5 -0
  25. mcp_agent/mcp/prompt_serialization.py +42 -0
  26. mcp_agent/mcp/prompts/prompt_load.py +51 -3
  27. mcp_agent/mcp_server/agent_server.py +61 -12
  28. mcp_agent/resources/examples/internal/agent.py +2 -2
  29. mcp_agent/resources/examples/internal/fastagent.config.yaml +5 -0
  30. mcp_agent/mcp/mcp_agent_server.py +0 -56
  31. {fast_agent_mcp-0.2.4.dist-info → fast_agent_mcp-0.2.6.dist-info}/WHEEL +0 -0
  32. {fast_agent_mcp-0.2.4.dist-info → fast_agent_mcp-0.2.6.dist-info}/entry_points.txt +0 -0
  33. {fast_agent_mcp-0.2.4.dist-info → fast_agent_mcp-0.2.6.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,13 @@
1
1
  # src/mcp_agent/mcp_server/agent_server.py
2
2
 
3
+ import asyncio
4
+
3
5
  from mcp.server.fastmcp import Context as MCPContext
4
6
  from mcp.server.fastmcp import FastMCP
5
7
 
6
- # Import the DirectAgentApp instead of AgentApp
8
+ import mcp_agent
9
+ import mcp_agent.core
10
+ import mcp_agent.core.prompt
7
11
  from mcp_agent.core.agent_app import AgentApp
8
12
 
9
13
 
@@ -14,7 +18,7 @@ class AgentMCPServer:
14
18
  self,
15
19
  agent_app: AgentApp,
16
20
  server_name: str = "FastAgent-MCP-Server",
17
- server_description: str = None,
21
+ server_description: str | None = None,
18
22
  ) -> None:
19
23
  self.agent_app = agent_app
20
24
  self.mcp_server = FastMCP(
@@ -26,28 +30,26 @@ class AgentMCPServer:
26
30
 
27
31
  def setup_tools(self) -> None:
28
32
  """Register all agents as MCP tools."""
29
- for agent_name, agent_proxy in self.agent_app._agents.items():
30
- self.register_agent_tools(agent_name, agent_proxy)
33
+ for agent_name, agent in self.agent_app._agents.items():
34
+ self.register_agent_tools(agent_name, agent)
31
35
 
32
- def register_agent_tools(self, agent_name: str, agent_proxy) -> None:
36
+ def register_agent_tools(self, agent_name: str, agent) -> None:
33
37
  """Register tools for a specific agent."""
34
38
 
35
39
  # Basic send message tool
36
40
  @self.mcp_server.tool(
37
- name=f"{agent_name}.send",
41
+ name=f"{agent_name}_send",
38
42
  description=f"Send a message to the {agent_name} agent",
39
43
  )
40
44
  async def send_message(message: str, ctx: MCPContext) -> str:
41
45
  """Send a message to the agent and return its response."""
42
46
 
43
47
  # Get the agent's context
44
- agent_context = None
45
- if hasattr(agent_proxy, "_agent") and hasattr(agent_proxy._agent, "context"):
46
- agent_context = agent_proxy._agent.context
48
+ agent_context = getattr(agent, "context", None)
47
49
 
48
50
  # Define the function to execute
49
51
  async def execute_send():
50
- return await agent_proxy.send(message)
52
+ return await agent.send(message)
51
53
 
52
54
  # Execute with bridged context
53
55
  if agent_context and ctx:
@@ -55,6 +57,25 @@ class AgentMCPServer:
55
57
  else:
56
58
  return await execute_send()
57
59
 
60
+ # Register a history prompt for this agent
61
+ @self.mcp_server.prompt(
62
+ name=f"{agent_name}_history",
63
+ description=f"Conversation history for the {agent_name} agent",
64
+ )
65
+ async def get_history_prompt() -> list:
66
+ """Return the conversation history as MCP messages."""
67
+ # Get the conversation history from the agent's LLM
68
+ if not hasattr(agent, "_llm") or agent._llm is None:
69
+ return []
70
+
71
+ # Convert the multipart message history to standard PromptMessages
72
+ multipart_history = agent._llm.message_history
73
+ prompt_messages = mcp_agent.core.prompt.Prompt.from_multipart(multipart_history)
74
+
75
+ # In FastMCP, we need to return the raw list of messages
76
+ # that matches the structure that FastMCP expects (list of dicts with role/content)
77
+ return [{"role": msg.role, "content": msg.content} for msg in prompt_messages]
78
+
58
79
  def run(self, transport: str = "sse", host: str = "0.0.0.0", port: int = 8000) -> None:
59
80
  """Run the MCP server."""
60
81
  if transport == "sse":
@@ -71,9 +92,19 @@ class AgentMCPServer:
71
92
  if transport == "sse":
72
93
  self.mcp_server.settings.host = host
73
94
  self.mcp_server.settings.port = port
74
- await self.mcp_server.run_sse_async()
95
+ try:
96
+ await self.mcp_server.run_sse_async()
97
+ except (asyncio.CancelledError, KeyboardInterrupt):
98
+ # Gracefully handle cancellation during shutdown
99
+ await self.shutdown()
100
+ pass
75
101
  else: # stdio
76
- await self.mcp_server.run_stdio_async()
102
+ try:
103
+ await self.mcp_server.run_stdio_async()
104
+ except (asyncio.CancelledError, KeyboardInterrupt):
105
+ # Gracefully handle cancellation during shutdown
106
+ await self.shutdown()
107
+ pass
77
108
 
78
109
  async def with_bridged_context(self, agent_context, mcp_context, func, *args, **kwargs):
79
110
  """
@@ -115,3 +146,21 @@ class AgentMCPServer:
115
146
  # Remove MCP context reference
116
147
  if hasattr(agent_context, "mcp_context"):
117
148
  delattr(agent_context, "mcp_context")
149
+
150
+ async def shutdown(self):
151
+ """Gracefully shutdown the MCP server and its resources."""
152
+ # Your MCP server may have additional cleanup code here
153
+ try:
154
+ # If your MCP server has a shutdown method, call it
155
+ if hasattr(self.mcp_server, "shutdown"):
156
+ await self.mcp_server.shutdown()
157
+
158
+ # Clean up any other resources
159
+ import asyncio
160
+
161
+ # Allow any pending tasks to clean up
162
+ await asyncio.sleep(0.5)
163
+ except Exception as e:
164
+ # Just log exceptions during shutdown, don't raise
165
+ print(f"Error during MCP server shutdown: {e}")
166
+ pass
@@ -7,13 +7,13 @@ fast = FastAgent("FastAgent Example")
7
7
 
8
8
 
9
9
  # Define the agent
10
- @fast.agent(servers=["category", "mcp_hfspace"])
10
+ @fast.agent(servers=["category", "mcp_hfspace","mcp_webcam"])
11
11
  #@fast.agent(name="test")
12
12
  async def main() -> None:
13
13
  # use the --model command line switch or agent arguments to change model
14
14
  async with fast.run() as agent:
15
15
  # await agent.prompt(agent_name="test")
16
- await agent.send("hello,world")
16
+ await agent()
17
17
 
18
18
 
19
19
  if __name__ == "__main__":
@@ -59,3 +59,8 @@ mcp:
59
59
  mcp_hfspace:
60
60
  command: "npx"
61
61
  args: ["@llmindset/mcp-hfspace"]
62
+
63
+ mcp_webcam:
64
+ command: "npx"
65
+ args: ["@llmindset/mcp-webcam"]
66
+
@@ -1,56 +0,0 @@
1
- import asyncio
2
-
3
- from mcp.server import NotificationOptions
4
- from mcp.server.fastmcp import FastMCP
5
- from mcp.server.stdio import stdio_server
6
-
7
- from mcp_agent.executor.temporal import get_temporal_client
8
- from mcp_agent.telemetry.tracing import setup_tracing
9
-
10
- app = FastMCP("mcp-agent-server")
11
-
12
- setup_tracing("mcp-agent-server")
13
-
14
-
15
- async def run() -> None:
16
- async with stdio_server() as (read_stream, write_stream):
17
- await app._mcp_server.run(
18
- read_stream,
19
- write_stream,
20
- app._mcp_server.create_initialization_options(
21
- notification_options=NotificationOptions(tools_changed=True, resources_changed=True)
22
- ),
23
- )
24
-
25
-
26
- @app.tool
27
- async def run_workflow(query: str) -> None:
28
- """Run the workflow given its name or id"""
29
- pass
30
-
31
-
32
- @app.tool
33
- async def pause_workflow(workflow_id: str) -> None:
34
- """Pause a running workflow."""
35
- temporal_client = await get_temporal_client()
36
- handle = temporal_client.get_workflow_handle(workflow_id)
37
- await handle.signal("pause")
38
-
39
-
40
- @app.tool
41
- async def resume_workflow(workflow_id: str) -> None:
42
- """Resume a paused workflow."""
43
- temporal_client = await get_temporal_client()
44
- handle = temporal_client.get_workflow_handle(workflow_id)
45
- await handle.signal("resume")
46
-
47
-
48
- async def provide_user_input(workflow_id: str, input_data: str) -> None:
49
- """Provide user/human input to a waiting workflow step."""
50
- temporal_client = await get_temporal_client()
51
- handle = temporal_client.get_workflow_handle(workflow_id)
52
- await handle.signal("human_input", input_data)
53
-
54
-
55
- if __name__ == "__main__":
56
- asyncio.run(run())