agent-mcp 0.1.3__py3-none-any.whl → 0.1.5__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 (57) hide show
  1. agent_mcp/__init__.py +66 -12
  2. agent_mcp/a2a_protocol.py +316 -0
  3. agent_mcp/agent_lightning_library.py +214 -0
  4. agent_mcp/camel_mcp_adapter.py +521 -0
  5. agent_mcp/claude_mcp_adapter.py +195 -0
  6. agent_mcp/cli.py +47 -0
  7. agent_mcp/google_ai_mcp_adapter.py +183 -0
  8. agent_mcp/heterogeneous_group_chat.py +412 -38
  9. agent_mcp/langchain_mcp_adapter.py +176 -43
  10. agent_mcp/llamaindex_mcp_adapter.py +410 -0
  11. agent_mcp/mcp_agent.py +26 -0
  12. agent_mcp/mcp_transport.py +11 -5
  13. agent_mcp/microsoft_agent_framework.py +591 -0
  14. agent_mcp/missing_frameworks.py +435 -0
  15. agent_mcp/openapi_protocol.py +616 -0
  16. agent_mcp/payments.py +804 -0
  17. agent_mcp/pydantic_ai_mcp_adapter.py +628 -0
  18. agent_mcp/registry.py +768 -0
  19. agent_mcp/security.py +864 -0
  20. {agent_mcp-0.1.3.dist-info → agent_mcp-0.1.5.dist-info}/METADATA +173 -49
  21. agent_mcp-0.1.5.dist-info/RECORD +62 -0
  22. {agent_mcp-0.1.3.dist-info → agent_mcp-0.1.5.dist-info}/WHEEL +1 -1
  23. agent_mcp-0.1.5.dist-info/entry_points.txt +4 -0
  24. agent_mcp-0.1.5.dist-info/top_level.txt +3 -0
  25. demos/__init__.py +1 -0
  26. demos/basic/__init__.py +1 -0
  27. demos/basic/framework_examples.py +108 -0
  28. demos/basic/langchain_camel_demo.py +272 -0
  29. demos/basic/simple_chat.py +355 -0
  30. demos/basic/simple_integration_example.py +51 -0
  31. demos/collaboration/collaborative_task_example.py +437 -0
  32. demos/collaboration/group_chat_example.py +130 -0
  33. demos/collaboration/simplified_crewai_example.py +39 -0
  34. demos/comprehensive_framework_demo.py +202 -0
  35. demos/langgraph/autonomous_langgraph_network.py +808 -0
  36. demos/langgraph/langgraph_agent_network.py +415 -0
  37. demos/langgraph/langgraph_collaborative_task.py +619 -0
  38. demos/langgraph/langgraph_example.py +227 -0
  39. demos/langgraph/run_langgraph_examples.py +213 -0
  40. demos/network/agent_network_example.py +381 -0
  41. demos/network/email_agent.py +130 -0
  42. demos/network/email_agent_demo.py +46 -0
  43. demos/network/heterogeneous_network_example.py +216 -0
  44. demos/network/multi_framework_example.py +199 -0
  45. demos/utils/check_imports.py +49 -0
  46. demos/workflows/autonomous_agent_workflow.py +248 -0
  47. demos/workflows/mcp_features_demo.py +353 -0
  48. demos/workflows/run_agent_collaboration_demo.py +63 -0
  49. demos/workflows/run_agent_collaboration_with_logs.py +396 -0
  50. demos/workflows/show_agent_interactions.py +107 -0
  51. demos/workflows/simplified_autonomous_demo.py +74 -0
  52. functions/main.py +144 -0
  53. functions/mcp_network_server.py +513 -0
  54. functions/utils.py +47 -0
  55. agent_mcp-0.1.3.dist-info/RECORD +0 -18
  56. agent_mcp-0.1.3.dist-info/entry_points.txt +0 -2
  57. agent_mcp-0.1.3.dist-info/top_level.txt +0 -1
@@ -0,0 +1,381 @@
1
+ """
2
+ Agent Network Example using MCPAgent.
3
+
4
+ This example demonstrates a network of agents that can communicate with each other
5
+ and share context, creating a simple agent social network. The user can interact
6
+ with any agent in the network, and agents can call other agents as tools.
7
+ """
8
+
9
+ import os
10
+ import json
11
+ from typing import Dict, List, Any, Optional
12
+ import time
13
+
14
+ # Import AutoGen components and MCPAgent
15
+ from autogen import UserProxyAgent
16
+ from agent_mcp import MCPAgent
17
+
18
+ # Check for API key
19
+ api_key = os.environ.get("OPENAI_API_KEY")
20
+ if not api_key:
21
+ raise ValueError("Please set the OPENAI_API_KEY environment variable")
22
+
23
+ # LLM configuration - using GPT-3.5 for faster responses, but can be switched to GPT-4
24
+ config = {
25
+ "config_list": [{"model": "gpt-3.5-turbo", "api_key": api_key}],
26
+ }
27
+
28
+ # Define agent specialties and personalities
29
+ AGENT_PROFILES = {
30
+ "coordinator": {
31
+ "name": "Coordinator",
32
+ "system_message": """You are the Coordinator agent who manages the network.
33
+ You can connect agents, share information, and help route messages to the right specialist.
34
+ You maintain a global view of the agent network and its capabilities.
35
+ Always be helpful, concise, and informative.""",
36
+ "specialty": "coordination",
37
+ "connections": ["researcher", "analyst", "creative", "planner"]
38
+ },
39
+ "researcher": {
40
+ "name": "Researcher",
41
+ "system_message": """You are the Researcher agent who specializes in finding information.
42
+ You love discovering facts, searching for evidence, and sharing your knowledge.
43
+ You're methodical, detail-oriented, and cite sources when possible.
44
+ Always be informative, thorough, and accurate.""",
45
+ "specialty": "research",
46
+ "connections": ["coordinator", "analyst"]
47
+ },
48
+ "analyst": {
49
+ "name": "Analyst",
50
+ "system_message": """You are the Analyst agent who excels at interpreting data.
51
+ You can evaluate information, identify patterns, and provide insights.
52
+ You're logical, critical, and good at understanding implications.
53
+ Always be analytical, balanced, and data-driven.""",
54
+ "specialty": "analysis",
55
+ "connections": ["coordinator", "researcher", "planner"]
56
+ },
57
+ "creative": {
58
+ "name": "Creative",
59
+ "system_message": """You are the Creative agent who generates innovative ideas.
60
+ You can think outside the box, create content, and suggest novel approaches.
61
+ You're imaginative, artistic, and full of unique perspectives.
62
+ Always be original, expressive, and inspirational.""",
63
+ "specialty": "creativity",
64
+ "connections": ["coordinator", "planner"]
65
+ },
66
+ "planner": {
67
+ "name": "Planner",
68
+ "system_message": """You are the Planner agent who designs strategies and organizes tasks.
69
+ You can create roadmaps, set milestones, and optimize workflows.
70
+ You're structured, forward-thinking, and efficient.
71
+ Always be practical, organized, and goal-oriented.""",
72
+ "specialty": "planning",
73
+ "connections": ["coordinator", "analyst", "creative"]
74
+ }
75
+ }
76
+
77
+ class AgentNetwork:
78
+ """A network of MCPAgents that can interact with each other and the user."""
79
+
80
+ def __init__(self):
81
+ self.agents = {}
82
+ self.user = None
83
+ self.current_topic = None
84
+
85
+ def create_network(self):
86
+ """Create all agents in the network and connect them.
87
+
88
+ This method initializes all agents defined in AGENT_PROFILES, creates a user proxy agent,
89
+ and establishes connections between agents based on their defined relationships.
90
+ Each agent is registered as a tool for its connected agents.
91
+ """
92
+ # First create all agents
93
+ for agent_id, profile in AGENT_PROFILES.items():
94
+ agent = MCPAgent(
95
+ name=profile["name"],
96
+ system_message=profile["system_message"],
97
+ llm_config=config,
98
+ human_input_mode="NEVER" # We'll handle human input separately
99
+ )
100
+
101
+ # Add agent-specific context
102
+ agent.update_context("profile", {
103
+ "specialty": profile["specialty"],
104
+ "connections": profile["connections"]
105
+ })
106
+
107
+ self.agents[agent_id] = agent
108
+ print(f"Created agent: {profile['name']} ({agent_id})")
109
+
110
+ # Create user proxy for human interaction
111
+ self.user = UserProxyAgent(
112
+ name="User",
113
+ human_input_mode="ALWAYS",
114
+ max_consecutive_auto_reply=0
115
+ )
116
+
117
+ # Now connect agents to each other
118
+ for agent_id, profile in AGENT_PROFILES.items():
119
+ agent = self.agents[agent_id]
120
+
121
+ # Register each connected agent as a tool
122
+ for connection_id in profile["connections"]:
123
+ if connection_id in self.agents:
124
+ connected_agent = self.agents[connection_id]
125
+ agent.register_agent_as_tool(connected_agent)
126
+ print(f"Connected {agent.name} to {connected_agent.name}")
127
+
128
+ print("\nAgent network created successfully!")
129
+
130
+ def set_topic(self, topic):
131
+ """Set a topic for discussion in the network.
132
+
133
+ Args:
134
+ topic: The topic to be discussed across the network.
135
+
136
+ This method updates the context of all agents with the new topic
137
+ and its timestamp for synchronized discussions.
138
+ """
139
+ self.current_topic = topic
140
+
141
+ # Share the topic with all agents
142
+ for agent_id, agent in self.agents.items():
143
+ agent.update_context("current_topic", {
144
+ "title": topic,
145
+ "timestamp": time.time()
146
+ })
147
+
148
+ print(f"\nTopic set: {topic}")
149
+
150
+ def interact_with_agent(self, agent_id):
151
+ """Allow the user to interact with a specific agent.
152
+
153
+ Args:
154
+ agent_id: The identifier of the agent to interact with.
155
+
156
+ This method enables direct conversation with a chosen agent,
157
+ supports topic-aware discussions, and allows switching between agents.
158
+ Type 'exit' to end conversation or 'switch:agent_id' to change agents.
159
+ """
160
+ if agent_id not in self.agents:
161
+ print(f"Agent '{agent_id}' not found. Available agents: {', '.join(self.agents.keys())}")
162
+ return
163
+
164
+ agent = self.agents[agent_id]
165
+ print(f"\n--- Starting interaction with {agent.name} ({agent_id}) ---")
166
+
167
+ if self.current_topic:
168
+ print(f"Current topic: {self.current_topic}")
169
+
170
+ # Get initial message from user
171
+ initial_message = input(f"\nYour message to {agent.name}: ")
172
+
173
+ # Create a conversation chain that includes the agent's context
174
+ messages = [{"role": "user", "content": initial_message}]
175
+
176
+ # Get agent response
177
+ response = agent.generate_reply(messages=messages, sender=self.user)
178
+ print(f"\n{agent.name}: {response}")
179
+
180
+ # Continue the conversation until user exits
181
+ while True:
182
+ # Check if user wants to exit
183
+ next_message = input("\nYour response (or type 'exit' to end, 'switch:agent_id' to change agents): ")
184
+
185
+ if next_message.lower() == 'exit':
186
+ print(f"--- Ending interaction with {agent.name} ---")
187
+ break
188
+
189
+ if next_message.lower().startswith('switch:'):
190
+ new_agent_id = next_message.split(':', 1)[1].strip()
191
+ print(f"--- Switching from {agent.name} to {new_agent_id} ---")
192
+ self.interact_with_agent(new_agent_id)
193
+ break
194
+
195
+ # Add to messages and get response
196
+ messages.append({"role": "user", "content": next_message})
197
+ response = agent.generate_reply(messages=messages, sender=self.user)
198
+ print(f"\n{agent.name}: {response}")
199
+
200
+ # Add agent response to message history
201
+ messages.append({"role": "assistant", "content": response})
202
+
203
+ def share_knowledge(self, from_agent_id, to_agent_id, knowledge_key, knowledge_value):
204
+ """Share specific knowledge from one agent to another.
205
+
206
+ Args:
207
+ from_agent_id: The source agent's identifier
208
+ to_agent_id: The target agent's identifier
209
+ knowledge_key: The key under which to store the knowledge
210
+ knowledge_value: The knowledge content to share
211
+
212
+ This method enables direct knowledge transfer between agents
213
+ by updating the target agent's context with specified information.
214
+ """
215
+ if from_agent_id not in self.agents or to_agent_id not in self.agents:
216
+ print("One or both agent IDs are invalid.")
217
+ return
218
+
219
+ # Get the agents
220
+ from_agent = self.agents[from_agent_id]
221
+ to_agent = self.agents[to_agent_id]
222
+
223
+ # Share the knowledge
224
+ to_agent.update_context(knowledge_key, knowledge_value)
225
+
226
+ print(f"Shared knowledge '{knowledge_key}' from {from_agent.name} to {to_agent.name}")
227
+
228
+ def broadcast_message(self, from_agent_id, message):
229
+ """Broadcast a message from one agent to all connected agents.
230
+
231
+ Args:
232
+ from_agent_id: The broadcasting agent's identifier
233
+ message: The message content to broadcast
234
+
235
+ This method sends a message to all agents connected to the source agent,
236
+ storing it in their contexts with timestamp information.
237
+ """
238
+ if from_agent_id not in self.agents:
239
+ print(f"Agent '{from_agent_id}' not found.")
240
+ return
241
+
242
+ from_agent = self.agents[from_agent_id]
243
+ profile = AGENT_PROFILES[from_agent_id]
244
+
245
+ # Send to all connected agents
246
+ for connection_id in profile["connections"]:
247
+ if connection_id in self.agents:
248
+ to_agent = self.agents[connection_id]
249
+
250
+ # Create a message in the agent's context
251
+ message_key = f"message_from_{from_agent_id}_{int(time.time())}"
252
+ message_value = {
253
+ "from": from_agent.name,
254
+ "content": message,
255
+ "timestamp": time.time()
256
+ }
257
+
258
+ to_agent.update_context(message_key, message_value)
259
+ print(f"Broadcast message from {from_agent.name} to {to_agent.name}")
260
+
261
+ def list_agents(self):
262
+ """List all agents in the network with their specialties.
263
+
264
+ This method prints a directory of all agents in the network,
265
+ showing their names, IDs, and specialties for easy reference.
266
+ """
267
+ print("\n--- Agent Network Directory ---")
268
+ for agent_id, agent in self.agents.items():
269
+ profile = agent.get_context("profile")
270
+ specialty = profile.get("specialty") if profile else "unknown"
271
+ print(f"- {agent.name} ({agent_id}): {specialty}")
272
+
273
+ def get_context(self, agent_id, key):
274
+ """Get a context value from an agent.
275
+
276
+ Args:
277
+ agent_id: The identifier of the agent
278
+ key: The context key to retrieve
279
+
280
+ Returns:
281
+ The context value if found, None otherwise
282
+ """
283
+ if agent_id not in self.agents:
284
+ return None
285
+
286
+ agent = self.agents[agent_id]
287
+ return agent.get_context(key)
288
+
289
+ def interact_with_agent_programmatically(self, agent_id, message):
290
+ """
291
+ Interact with an agent programmatically without requiring user input.
292
+
293
+ This method is similar to interact_with_agent but allows for automation
294
+ in scripts and demonstrations.
295
+
296
+ Args:
297
+ agent_id: The ID of the agent to interact with
298
+ message: The message to send to the agent
299
+
300
+ Returns:
301
+ The agent's response as a string
302
+ """
303
+ if agent_id not in self.agents:
304
+ print(f"Agent '{agent_id}' not found in the network.")
305
+ return "Error: Agent not found"
306
+
307
+ agent = self.agents[agent_id]
308
+
309
+ # Include current topic in the context if available
310
+ if self.current_topic:
311
+ # Check if agent has the current_topic in context
312
+ if not agent.has_context("current_topic"):
313
+ agent.update_context("current_topic", self.current_topic)
314
+
315
+ # Format the user message
316
+ print(f"\nMessage to {agent.name}: {message}")
317
+
318
+ # Send message to the agent
319
+ response = agent.generate_reply(
320
+ messages=[{"role": "user", "content": message}]
321
+ )
322
+
323
+ print(f"\n{agent.name}: {response}")
324
+ return response
325
+
326
+ def main():
327
+ """Run the agent network example."""
328
+ print("=== Agent Network Example ===")
329
+ print("Creating a network of specialized agents that can communicate with each other.")
330
+
331
+ # Create the agent network
332
+ network = AgentNetwork()
333
+ network.create_network()
334
+
335
+ # Main interaction loop
336
+ while True:
337
+ print("\n=== Agent Network Menu ===")
338
+ print("1. List all agents")
339
+ print("2. Set a discussion topic")
340
+ print("3. Talk to an agent")
341
+ print("4. Share knowledge between agents")
342
+ print("5. Broadcast a message")
343
+ print("6. Exit")
344
+
345
+ choice = input("\nSelect an option (1-6): ")
346
+
347
+ if choice == "1":
348
+ network.list_agents()
349
+
350
+ elif choice == "2":
351
+ topic = input("Enter a topic for discussion: ")
352
+ network.set_topic(topic)
353
+
354
+ elif choice == "3":
355
+ network.list_agents()
356
+ agent_id = input("\nEnter the agent ID you want to talk to: ")
357
+ network.interact_with_agent(agent_id)
358
+
359
+ elif choice == "4":
360
+ network.list_agents()
361
+ from_agent = input("\nEnter the source agent ID: ")
362
+ to_agent = input("Enter the target agent ID: ")
363
+ key = input("Enter the knowledge key: ")
364
+ value = input("Enter the knowledge value: ")
365
+ network.share_knowledge(from_agent, to_agent, key, value)
366
+
367
+ elif choice == "5":
368
+ network.list_agents()
369
+ from_agent = input("\nEnter the broadcasting agent ID: ")
370
+ message = input("Enter the message to broadcast: ")
371
+ network.broadcast_message(from_agent, message)
372
+
373
+ elif choice == "6":
374
+ print("Exiting the Agent Network Example. Goodbye!")
375
+ break
376
+
377
+ else:
378
+ print("Invalid option. Please try again.")
379
+
380
+ if __name__ == "__main__":
381
+ main()
@@ -0,0 +1,130 @@
1
+ """Simple Email Agent Example
2
+
3
+ This example shows how to create a simple email agent using just the @mcp_agent decorator.
4
+ The decorator automatically handles all the MCP communication functionality.
5
+ """
6
+
7
+ import os
8
+ import smtplib
9
+ import logging
10
+ import json
11
+ from email.mime.text import MIMEText
12
+ from email.mime.multipart import MIMEMultipart
13
+ from typing import Dict, Any
14
+ from agent_mcp import mcp_agent
15
+ from agent_mcp.langgraph_mcp_adapter import LangGraphMCPAdapter
16
+ from langgraph.graph import StateGraph, START, END
17
+ from dotenv import load_dotenv
18
+ import re
19
+
20
+ # Configure logging
21
+ logging.basicConfig(level=logging.INFO)
22
+ logger = logging.getLogger(__name__)
23
+
24
+ load_dotenv()
25
+ print("Email Agent is starting...")
26
+
27
+
28
+ @mcp_agent(mcp_id="EmailAgent")
29
+ class EmailAgent(LangGraphMCPAdapter):
30
+ """An agent capable of sending emails through SMTP."""
31
+
32
+ def __init__(self):
33
+ """Initialize email agent with SMTP settings"""
34
+ # Email configuration
35
+ self.smtp_server = os.getenv("SMTP_SERVER", "smtp.gmail.com")
36
+ self.smtp_port = int(os.getenv("SMTP_PORT", "587"))
37
+ self.email_address = os.getenv("EMAIL_ADDRESS")
38
+ self.email_password = os.getenv("EMAIL_PASSWORD")
39
+
40
+ if not all([self.email_address, self.email_password]):
41
+ logger.warning("Email credentials not found in environment variables")
42
+
43
+ # Create workflow using dict for state
44
+ workflow = StateGraph(dict)
45
+ workflow.add_node("send_email", self.send_email)
46
+ workflow.add_edge(START, "send_email")
47
+ workflow.add_edge("send_email", END)
48
+
49
+ # Initialize adapter with workflow but preserve transport
50
+ transport = getattr(self, 'transport', None)
51
+ super().__init__(name="EmailAgent", workflow=workflow, state_type=dict)
52
+ if transport:
53
+ self.transport = transport
54
+
55
+ async def send_email(self, state_dict: dict):
56
+ """Send an email using configured SMTP settings"""
57
+ try:
58
+ print("Email Agent is about to send email...")
59
+ print(f"State dict received: {state_dict}")
60
+
61
+ # Get the task message (could be in message or content field)
62
+ task = state_dict.get('message') or state_dict.get('content')
63
+ print(f"Task received: {task}")
64
+
65
+ result = None
66
+ if not all([self.email_address, self.email_password]):
67
+ result = "Error: Email credentials not configured"
68
+ return {"message": task, "result": result}
69
+
70
+ # Extract content from task
71
+ if isinstance(task, dict):
72
+ if 'text' in task:
73
+ try:
74
+ content = json.loads(task['text'])
75
+ except json.JSONDecodeError:
76
+ content = task
77
+ else:
78
+ content = task
79
+ else:
80
+ content = task
81
+
82
+ print(f"Content after parsing: {content}")
83
+
84
+ # Extract parameters
85
+ params = content.get('email_params', content)
86
+ to_address = params.get('to_address')
87
+ subject = params.get('subject')
88
+ body = params.get('body') or content.get('content')
89
+ body = re.sub(r'^Subject:.*?\n', '', body, flags=re.IGNORECASE).strip()
90
+
91
+ cc_address = params.get('cc_address')
92
+
93
+ print(f"Extracted params: to={to_address}, subject={subject}, body={body}, cc={cc_address}")
94
+
95
+ if not all([to_address, subject, body]):
96
+ result = "Error: Missing required email parameters"
97
+ logger.error(f"Missing email parameters. Got: {params}")
98
+ return {"message": task, "result": result}
99
+
100
+ # Create message
101
+ msg = MIMEMultipart()
102
+ msg['From'] = self.email_address
103
+ msg['To'] = to_address
104
+ msg['Subject'] = subject
105
+
106
+ if cc_address:
107
+ msg['Cc'] = cc_address
108
+
109
+ # Add body
110
+ msg.attach(MIMEText(body, 'plain'))
111
+
112
+ # Connect to SMTP server
113
+ with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
114
+ server.starttls()
115
+ server.login(self.email_address, self.email_password)
116
+
117
+ # Send email
118
+ recipients = [to_address]
119
+ if cc_address:
120
+ recipients.append(cc_address)
121
+ server.sendmail(self.email_address, recipients, msg.as_string())
122
+
123
+ logger.info(f"Email sent successfully to {to_address}")
124
+ result = "Email sent successfully"
125
+ return {"message": task, "result": result}
126
+
127
+ except Exception as e:
128
+ result = f"Error sending email: {str(e)}"
129
+ logger.error(f"Error sending email: {e}")
130
+ return {"message": task, "result": result}
@@ -0,0 +1,46 @@
1
+ """Example demonstrating how to create a simple MCP-compatible email agent."""
2
+
3
+ import os
4
+ import asyncio
5
+ from dotenv import load_dotenv
6
+ from email_agent import EmailAgent
7
+
8
+ # Load environment variables
9
+ load_dotenv()
10
+
11
+ async def demonstrate_email_agent():
12
+ # Create and initialize the email agent
13
+ email_agent = EmailAgent()
14
+
15
+ # Connect to the MCP network
16
+ await email_agent.connect()
17
+ print("Email agent is connected and ready to receive tasks")
18
+
19
+
20
+ # Start message and task processors
21
+ email_agent.run()
22
+
23
+ try:
24
+ # Wait for interrupt - the adapter handles message processing
25
+ while True:
26
+ await asyncio.sleep(1)
27
+ except KeyboardInterrupt:
28
+ print("\nShutting down email agent...")
29
+ await email_agent.disconnect()
30
+
31
+ if __name__ == "__main__":
32
+ # Check for required environment variables
33
+ required_vars = [
34
+ "EMAIL_ADDRESS",
35
+ "EMAIL_PASSWORD",
36
+ "SMTP_SERVER",
37
+ "SMTP_PORT"
38
+ ]
39
+ missing_vars = [var for var in required_vars if not os.getenv(var)]
40
+
41
+ if missing_vars:
42
+ print(f"Missing required environment variables: {', '.join(missing_vars)}")
43
+ print("Please set them in your .env file")
44
+ else:
45
+ print("Starting email agent...")
46
+ asyncio.run(demonstrate_email_agent())