refactor: Enhance multi_mcp_agent with SQLite database integration and update requirements

- Integrated SQLite database for memory management in multi_mcp_agent.
- Updated memory handling to use the new database instance.
This commit is contained in:
Shubhamsaboo
2025-11-09 15:08:25 -08:00
parent 62f760c18e
commit 78e7898cae
8 changed files with 14 additions and 287 deletions

View File

@@ -1,16 +1,11 @@
import asyncio
import json
import os
import sys
import uuid
from typing import List, Optional
from textwrap import dedent
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.mcp import MultiMCPTools
from agno.memory.v2 import Memory
from mcp import StdioServerParameters
from agno.utils.pprint import apprint_run_response
from agno.db.sqlite import SqliteDb
from dotenv import load_dotenv
# Load environment variables
@@ -65,6 +60,9 @@ async def main():
"npx @gongrzhe/server-gmail-autoauth-mcp"
]
# Setup database for memory
db = SqliteDb(db_file="tmp/multi_mcp_agent.db")
# Start the MCP Tools session
async with MultiMCPTools(mcp_servers, env=env) as mcp_tools:
print("✅ Successfully connected to all MCP servers!")
@@ -126,10 +124,11 @@ async def main():
REMEMBER: You're not just answering questions - you're a productivity multiplier. Think big, suggest workflows, and help users achieve more than they imagined possible!
"""),
markdown=True,
show_tool_calls=True,
debug_mode=True,
retries=3,
memory=Memory(),
add_history_to_messages=True,
db=db,
enable_user_memories=True,
add_history_to_context=True,
num_history_runs=10, # Increased for better context retention
)

View File

@@ -1,4 +1,4 @@
agno
agno>=2.2.10
openai
mcp
python-dotenv

View File

@@ -106,7 +106,3 @@ You can exit the conversation at any time by typing `exit`, `quit`, `bye`, or `g
- "Add a comment to the first paragraph saying 'This looks good!'"
- "Search for any mentions of meetings"
- "Summarize our conversation so far"
## License
MIT

View File

@@ -27,6 +27,7 @@ async def main():
openai_api_key = OPENAI_API_KEY
# Prompt for page ID first
page_id = None
if len(sys.argv) > 1:
# Use command-line argument if provided
page_id = sys.argv[1]
@@ -39,12 +40,13 @@ async def main():
user_input = input("> ")
# If user input is empty, use default
# If user input is empty, prompt again
if user_input.strip():
page_id = user_input.strip()
print(f"Using provided page ID: {page_id}")
else:
print(f"Using default page ID: {page_id}")
print("❌ Error: Page ID is required. Please provide a Notion page ID.")
return
# Generate unique user and session IDs for this terminal session
user_id = f"user_{uuid.uuid4().hex[:8]}"

View File

@@ -1,4 +1,4 @@
agno
agno>=2.2.10
python-dotenv
mcp
openai

View File

@@ -1,211 +0,0 @@
import os
import sys
import json
import importlib.util
from typing import Dict, Any
print("CWD:", os.getcwd(), file=sys.stderr)
print("FILES IN CWD:", os.listdir(), file=sys.stderr)
print("TOOLS_DIR:", os.path.join(os.path.dirname(__file__), 'tools'), file=sys.stderr)
TOOLS_DIR = os.path.join(os.path.dirname(__file__), 'tools')
class ToolManager:
def __init__(self, tools_dir: str):
self.tools_dir = tools_dir
self.commands = {} # command_name -> (tool_name, function)
self.load_tools()
def load_tools(self):
if not os.path.isdir(self.tools_dir):
return
for tool_name in os.listdir(self.tools_dir):
tool_path = os.path.join(self.tools_dir, tool_name)
if not os.path.isdir(tool_path):
continue
mcp_json_path = os.path.join(tool_path, 'mcp.json')
if not os.path.isfile(mcp_json_path):
continue
with open(mcp_json_path, 'r', encoding='utf-8') as f:
meta = json.load(f)
entry_point = meta.get('entry_point')
if not entry_point:
continue
entry_path = os.path.join(tool_path, entry_point)
if not os.path.isfile(entry_path):
continue
# Dynamically import the tool's entry point
spec = importlib.util.spec_from_file_location(f"{tool_name}_module", entry_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Register commands
for cmd, cmd_meta in meta.get('commands', {}).items():
if hasattr(module, cmd):
self.commands[cmd] = (tool_name, getattr(module, cmd))
def dispatch(self, method: str, params: Dict[str, Any]):
if method not in self.commands:
raise Exception(f"Unknown command: {method}")
tool_name, func = self.commands[method]
return func(params)
def jsonrpc_response(result, id):
response = {
"jsonrpc": "2.0",
"id": id
}
if result is not None:
response["result"] = result
return json.dumps(response)
def jsonrpc_error(message, id=None, code=-32603):
response = {
"jsonrpc": "2.0",
"error": {
"code": code,
"message": message
}
}
# Only include id if it's not None (for notifications, id can be None)
if id is not None:
response["id"] = id
return json.dumps(response)
def handle_initialize(params):
return {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": {},
"resources": {},
"prompts": {}
},
"serverInfo": {
"name": "native-mcp-server",
"version": "1.0.0"
}
}
def handle_initialized(params):
# Notification - no response needed
return None
def handle_list_resources(params):
return {"resources": []}
def handle_list_prompts(params):
return {"prompts": []}
def handle_list_tools(params):
tool_manager = ToolManager(TOOLS_DIR)
tools = []
for cmd, (tool_name, func) in tool_manager.commands.items():
# Load the mcp.json to get command metadata
tool_path = os.path.join(tool_manager.tools_dir, tool_name)
mcp_json_path = os.path.join(tool_path, 'mcp.json')
with open(mcp_json_path, 'r', encoding='utf-8') as f:
meta = json.load(f)
cmd_meta = meta.get('commands', {}).get(cmd, {})
tool_info = {
"name": cmd,
"description": cmd_meta.get('description', f'Tool: {cmd}'),
"inputSchema": {
"type": "object",
"properties": cmd_meta.get('params', {}),
"required": list(cmd_meta.get('params', {}).keys())
}
}
tools.append(tool_info)
return {"tools": tools}
def handle_call_tool(params):
tool_manager = ToolManager(TOOLS_DIR)
tool_name = params.get('name')
arguments = params.get('arguments', {})
if tool_name not in tool_manager.commands:
raise Exception(f"Unknown tool: {tool_name}")
result = tool_manager.dispatch(tool_name, arguments)
return {
"content": [
{
"type": "text",
"text": json.dumps(result, indent=2)
}
]
}
def main():
tool_manager = ToolManager(TOOLS_DIR)
# MCP protocol handlers
mcp_handlers = {
"initialize": handle_initialize,
"notifications/initialized": handle_initialized,
"tools/list": handle_list_tools,
"tools/call": handle_call_tool,
"resources/list": handle_list_resources,
"prompts/list": handle_list_prompts
}
while True:
try:
line = sys.stdin.readline()
if not line:
break
# Skip empty lines
line = line.strip()
if not line:
continue
req = json.loads(line)
method = req.get('method')
params = req.get('params', {})
id = req.get('id')
# Handle notifications (no id field, no response expected)
if id is None and method:
if method in mcp_handlers:
try:
mcp_handlers[method](params)
except Exception as e:
# Notifications don't send error responses
print(f"Error in notification {method}: {e}", file=sys.stderr)
continue
# Handle requests (have id field, response expected)
if not method:
sys.stdout.write(jsonrpc_error("Missing method", id) + '\n')
sys.stdout.flush()
continue
try:
# Handle MCP protocol methods
if method in mcp_handlers:
result = mcp_handlers[method](params)
if result is not None: # Only send response if not a notification
sys.stdout.write(jsonrpc_response(result, id) + '\n')
sys.stdout.flush()
else:
# Try to dispatch to tools (for backward compatibility)
result = tool_manager.dispatch(method, params)
sys.stdout.write(jsonrpc_response(result, id) + '\n')
sys.stdout.flush()
except Exception as e:
sys.stdout.write(jsonrpc_error(str(e), id) + '\n')
sys.stdout.flush()
except json.JSONDecodeError as e:
print(f"JSON decode error: {e}", file=sys.stderr)
sys.stdout.write(jsonrpc_error(f"Invalid JSON: {e}", None) + '\n')
sys.stdout.flush()
except Exception as e:
print(f"Server error: {e}", file=sys.stderr)
sys.stdout.write(jsonrpc_error(f"Server error: {e}", None) + '\n')
sys.stdout.flush()
if __name__ == "__main__":
main()

View File

@@ -1,59 +0,0 @@
# React Native MCP Agent
This project is an AI agent designed to interact with React Native applications using the Model Context Protocol (MCP). It enables advanced automation, reasoning, and integration capabilities for mobile app workflows.
## Features
- MCP server for agent communication
- Native integration with React Native apps
- Extensible agent logic in Python
- Example usage and quickstart scripts
## Getting Started
### Prerequisites
- Python 3.8+
- React Native development environment
- Node.js and npm
### Installation
1. Add the React Native MCP agent to your project:
```bash
npm install @mcp/react-native-agent
```
2. No external dependencies required for core MCP server
### Usage
1. Import the agent in your React Native application:
```javascript
import { MCPAgent } from '@mcp/react-native-agent';
```
2. Initialize the agent:
```javascript
const agent = new MCPAgent();
await agent.initialize();
```
3. Execute commands:
```javascript
const result = await agent.execute('analyze-screen');
```
- For native integration, see `native.py` for example functions and usage.
## File Structure
- `mcp_server.py` — MCP server implementation
- `native.py` — Native React Native integration logic
## Customization
- Extend `native.py` for additional React Native features.