mirror of
https://github.com/tcsenpai/agenticSeek.git
synced 2025-06-03 01:30:11 +00:00
Feat : MCP agent
This commit is contained in:
parent
887060acdf
commit
442bb4a340
7
cli.py
7
cli.py
@ -7,7 +7,7 @@ import asyncio
|
||||
|
||||
from sources.llm_provider import Provider
|
||||
from sources.interaction import Interaction
|
||||
from sources.agents import Agent, CoderAgent, CasualAgent, FileAgent, PlannerAgent, BrowserAgent
|
||||
from sources.agents import Agent, CoderAgent, CasualAgent, FileAgent, PlannerAgent, BrowserAgent, McpAgent
|
||||
from sources.browser import Browser, create_driver
|
||||
from sources.utility import pretty_print
|
||||
|
||||
@ -48,7 +48,10 @@ async def main():
|
||||
provider=provider, verbose=False, browser=browser),
|
||||
PlannerAgent(name="Planner",
|
||||
prompt_path=f"prompts/{personality_folder}/planner_agent.txt",
|
||||
provider=provider, verbose=False, browser=browser)
|
||||
provider=provider, verbose=False, browser=browser),
|
||||
McpAgent(name="MCP Agent",
|
||||
prompt_path=f"prompts/{personality_folder}/mcp_agent.txt",
|
||||
provider=provider, verbose=False),
|
||||
]
|
||||
|
||||
interaction = Interaction(agents,
|
||||
|
66
prompts/base/mcp_agent.txt
Normal file
66
prompts/base/mcp_agent.txt
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
You are an agent designed to utilize the MCP protocol to accomplish tasks.
|
||||
|
||||
The MCP provide you with a standard way to use tools and data sources like databases, APIs, or apps (e.g., GitHub, Slack).
|
||||
|
||||
The are thousands of MCPs protocol that can accomplish a variety of tasks, for example:
|
||||
- get weather information
|
||||
- get stock data information
|
||||
- Use software like blender
|
||||
- Get messages from teams, stack, messenger
|
||||
- Read and send email
|
||||
|
||||
Anything is possible with MCP.
|
||||
|
||||
To search for MCP a special format:
|
||||
|
||||
- Example 1:
|
||||
|
||||
User: what's the stock market of IBM like today?:
|
||||
|
||||
You: I will search for mcp to find information about IBM stock market.
|
||||
|
||||
```mcp_finder
|
||||
stock
|
||||
```
|
||||
|
||||
You search query must be one or two words at most.
|
||||
|
||||
This will provide you with informations about a specific MCP such as the json of parameters needed to use it.
|
||||
|
||||
For example, you might see:
|
||||
-------
|
||||
Name: Search Stock News
|
||||
Usage name: @Cognitive-Stack/search-stock-news-mcp
|
||||
Tools: [{'name': 'search-stock-news', 'description': 'Search for stock-related news using Tavily API', 'inputSchema': {'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['symbol', 'companyName'], 'properties': {'symbol': {'type': 'string', 'description': "Stock symbol to search for (e.g., 'AAPL')"}, 'companyName': {'type': 'string', 'description': 'Full company name to include in the search'}}, 'additionalProperties': False}}]
|
||||
-------
|
||||
|
||||
You can then a MCP like so:
|
||||
|
||||
```<usage name>
|
||||
{
|
||||
"tool": "<tool name (without @)>",
|
||||
"inputSchema": {<inputSchema json for the tool>}
|
||||
}
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
Now that I know how to use the MCP, I will choose the search-stock-news tool and execute it to find out IBM stock market.
|
||||
|
||||
```Cognitive-Stack/search-stock-news-mcp
|
||||
{
|
||||
"tool": "search-stock-news",
|
||||
"inputSchema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": ["symbol"],
|
||||
"properties": {
|
||||
"symbol": "IBM"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the schema require an information that you don't have ask the users for the information.
|
||||
|
62
prompts/jarvis/mcp_agent.txt
Normal file
62
prompts/jarvis/mcp_agent.txt
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
You are an agent designed to utilize the MCP protocol to accomplish tasks.
|
||||
|
||||
The MCP provide you with a standard way to use tools and data sources like databases, APIs, or apps (e.g., GitHub, Slack).
|
||||
|
||||
The are thousands of MCPs protocol that can accomplish a variety of tasks, for example:
|
||||
- get weather information
|
||||
- get stock data information
|
||||
- Use software like blender
|
||||
- Get messages from teams, stack, messenger
|
||||
- Read and send email
|
||||
|
||||
Anything is possible with MCP.
|
||||
|
||||
To search for MCP a special format:
|
||||
|
||||
- Example 1:
|
||||
|
||||
User: what's the stock market of IBM like today?:
|
||||
|
||||
You: I will search for mcp to find information about IBM stock market.
|
||||
|
||||
```mcp_finder
|
||||
stock
|
||||
```
|
||||
|
||||
This will provide you with informations about a specific MCP such as the json of parameters needed to use it.
|
||||
|
||||
For example, you might see:
|
||||
-------
|
||||
Name: Search Stock News
|
||||
Usage name: @Cognitive-Stack/search-stock-news-mcp
|
||||
Tools: [{'name': 'search-stock-news', 'description': 'Search for stock-related news using Tavily API', 'inputSchema': {'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['symbol', 'companyName'], 'properties': {'symbol': {'type': 'string', 'description': "Stock symbol to search for (e.g., 'AAPL')"}, 'companyName': {'type': 'string', 'description': 'Full company name to include in the search'}}, 'additionalProperties': False}}]
|
||||
-------
|
||||
|
||||
You can then a MCP like so:
|
||||
|
||||
```<usage name>
|
||||
{
|
||||
"tool": "<tool name (without @)>",
|
||||
"inputSchema": {<inputSchema json for the tool>}
|
||||
}
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
Now that I know how to use the MCP, I will choose the search-stock-news tool and execute it to find out IBM stock market.
|
||||
|
||||
```Cognitive-Stack/search-stock-news-mcp
|
||||
{
|
||||
"tool": "search-stock-news",
|
||||
"inputSchema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": ["symbol"],
|
||||
"properties": {
|
||||
"symbol": "IBM"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -5,5 +5,6 @@ from .casual_agent import CasualAgent
|
||||
from .file_agent import FileAgent
|
||||
from .planner_agent import PlannerAgent
|
||||
from .browser_agent import BrowserAgent
|
||||
from .mcp_agent import McpAgent
|
||||
|
||||
__all__ = ["Agent", "CoderAgent", "CasualAgent", "FileAgent", "PlannerAgent", "BrowserAgent"]
|
||||
__all__ = ["Agent", "CoderAgent", "CasualAgent", "FileAgent", "PlannerAgent", "BrowserAgent", "McpAgent"]
|
||||
|
@ -90,6 +90,12 @@ class Agent():
|
||||
raise TypeError("Tool must be a callable object (a method)")
|
||||
self.tools[name] = tool
|
||||
|
||||
def get_tools_name(self) -> list:
|
||||
"""
|
||||
Get the list of tools names.
|
||||
"""
|
||||
return list(self.tools.keys())
|
||||
|
||||
def load_prompt(self, file_path: str) -> str:
|
||||
try:
|
||||
with open(file_path, 'r', encoding="utf-8") as f:
|
||||
@ -235,11 +241,13 @@ class Agent():
|
||||
answer = "I will execute:\n" + answer # there should always be a text before blocks for the function that display answer
|
||||
|
||||
self.success = True
|
||||
self.blocks_result = []
|
||||
for name, tool in self.tools.items():
|
||||
feedback = ""
|
||||
blocks, save_path = tool.load_exec_block(answer)
|
||||
|
||||
if blocks != None:
|
||||
pretty_print(f"Executing {len(blocks)} {name} blocks...", color="status")
|
||||
for block in blocks:
|
||||
self.show_block(block)
|
||||
output = tool.execute([block])
|
||||
|
@ -62,14 +62,14 @@ class CoderAgent(Agent):
|
||||
animate_thinking("Executing code...", color="status")
|
||||
self.status_message = "Executing code..."
|
||||
self.logger.info(f"Attempt {attempt + 1}:\n{answer}")
|
||||
exec_success, _ = self.execute_modules(answer)
|
||||
exec_success, feedback = self.execute_modules(answer)
|
||||
self.logger.info(f"Execution result: {exec_success}")
|
||||
answer = self.remove_blocks(answer)
|
||||
self.last_answer = answer
|
||||
await asyncio.sleep(0)
|
||||
if exec_success and self.get_last_tool_type() != "bash":
|
||||
break
|
||||
pretty_print("Execution failure", color="failure")
|
||||
pretty_print(f"Execution failure:\n{feedback}", color="failure")
|
||||
pretty_print("Correcting code...", color="status")
|
||||
self.status_message = "Correcting code..."
|
||||
attempt += 1
|
||||
|
70
sources/agents/mcp_agent.py
Normal file
70
sources/agents/mcp_agent.py
Normal file
@ -0,0 +1,70 @@
|
||||
import os
|
||||
import asyncio
|
||||
|
||||
from sources.utility import pretty_print, animate_thinking
|
||||
from sources.agents.agent import Agent
|
||||
from sources.tools.mcpFinder import MCP_finder
|
||||
|
||||
# NOTE MCP agent is an active work in progress, not functional yet.
|
||||
|
||||
class McpAgent(Agent):
|
||||
|
||||
def __init__(self, name, prompt_path, provider, verbose=False):
|
||||
"""
|
||||
The mcp agent is a special agent for using MCPs.
|
||||
MCP agent will be disabled if the user does not explicitly set the MCP_FINDER_API_KEY in environment variable.
|
||||
"""
|
||||
super().__init__(name, prompt_path, provider, verbose, None)
|
||||
keys = self.get_api_keys()
|
||||
self.tools = {
|
||||
"mcp_finder": MCP_finder(keys["mcp_finder"]),
|
||||
# add mcp tools here
|
||||
}
|
||||
self.role = "mcp"
|
||||
self.type = "mcp_agent"
|
||||
self.enabled = True
|
||||
|
||||
def get_api_keys(self) -> dict:
|
||||
"""
|
||||
Returns the API keys for the tools.
|
||||
"""
|
||||
api_key_mcp_finder = os.getenv("MCP_FINDER_API_KEY")
|
||||
if not api_key_mcp_finder or api_key_mcp_finder == "":
|
||||
pretty_print("MCP Finder API key not found. Please set the MCP_FINDER_API_KEY environment variable.", color="failure")
|
||||
pretty_print("MCP Finder disabled.", color="failure")
|
||||
self.enabled = False
|
||||
return {
|
||||
"mcp_finder": api_key_mcp_finder
|
||||
}
|
||||
|
||||
def expand_prompt(self, prompt):
|
||||
"""
|
||||
Expands the prompt with the tools available.
|
||||
"""
|
||||
tools_name = self.get_tools_name()
|
||||
tools_str = ", ".join(tools_name)
|
||||
prompt += f"""
|
||||
You can use the following tools and MCPs:
|
||||
{tools_str}
|
||||
"""
|
||||
return prompt
|
||||
|
||||
async def process(self, prompt, speech_module) -> str:
|
||||
if self.enabled == False:
|
||||
return "MCP Agent is disabled."
|
||||
prompt = self.expand_prompt(prompt)
|
||||
self.memory.push('user', prompt)
|
||||
working = True
|
||||
while working == True:
|
||||
animate_thinking("Thinking...", color="status")
|
||||
answer, reasoning = await self.llm_request()
|
||||
exec_success, _ = self.execute_modules(answer)
|
||||
answer = self.remove_blocks(answer)
|
||||
self.last_answer = answer
|
||||
self.status_message = "Ready"
|
||||
if len(self.blocks_result) == 0:
|
||||
working = False
|
||||
return answer, reasoning
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
@ -141,6 +141,9 @@ class AgentRouter:
|
||||
("Search the web for tips on improving coding skills", "LOW"),
|
||||
("Write a Python script to count words in a text file", "LOW"),
|
||||
("Search the web for restaurant", "LOW"),
|
||||
("Use a MCP to find the latest stock market data", "LOW"),
|
||||
("Use a MCP to send an email to my boss", "LOW"),
|
||||
("Could you use a MCP to find the latest news on climate change?", "LOW"),
|
||||
("Create a simple HTML page with CSS styling", "LOW"),
|
||||
("Use file.txt and then use it to ...", "HIGH"),
|
||||
("Yo, what’s good? Find my ‘mixtape.mp3’ real quick", "LOW"),
|
||||
@ -162,6 +165,7 @@ class AgentRouter:
|
||||
("Find a public API for book data and create a Flask app to list bestsellers", "HIGH"),
|
||||
("Organize my desktop files by extension and then write a script to list them", "HIGH"),
|
||||
("Find the latest research on renewable energy and build a web app to display it", "HIGH"),
|
||||
("search online for popular sci-fi movies from 2024 and pick three to watch tonight. Save the list in movie_night.txt", "HIGH"),
|
||||
("can you find vitess repo, clone it and install by following the readme", "HIGH"),
|
||||
("Create a JavaScript game using Phaser.js with multiple levels", "HIGH"),
|
||||
("Search the web for the latest trends in web development and build a sample site", "HIGH"),
|
||||
@ -330,6 +334,11 @@ class AgentRouter:
|
||||
("can you make a web app in python that use the flask framework", "code"),
|
||||
("can you build a web server in go that serve a simple html page", "code"),
|
||||
("can you find out who Jacky yougouri is ?", "web"),
|
||||
("Can you use MCP to find stock market for IBM ?", "mcp"),
|
||||
("Can you use MCP to to export my contacts to a csv file?", "mcp"),
|
||||
("Can you use a MCP to find write notes to flomo", "mcp"),
|
||||
("Can you use a MCP to query my calendar and find the next meeting?", "mcp"),
|
||||
("Can you use a mcp to get the distance between Shanghai and Paris?", "mcp"),
|
||||
("Setup a new flutter project called 'new_flutter_project'", "files"),
|
||||
("can you create a new project called 'new_project'", "files"),
|
||||
("can you make a simple web app that display a list of files in my dir", "code"),
|
||||
|
@ -17,6 +17,8 @@ class BashInterpreter(Tools):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tag = "bash"
|
||||
self.name = "Bash Interpreter"
|
||||
self.description = "This tool allows the agent to execute bash commands."
|
||||
|
||||
def language_bash_attempt(self, command: str):
|
||||
"""
|
||||
|
@ -15,6 +15,8 @@ class CInterpreter(Tools):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tag = "c"
|
||||
self.name = "C Interpreter"
|
||||
self.description = "This tool allows the agent to execute C code."
|
||||
|
||||
def execute(self, codes: str, safety=False) -> str:
|
||||
"""
|
||||
|
@ -15,6 +15,8 @@ class GoInterpreter(Tools):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tag = "go"
|
||||
self.name = "Go Interpreter"
|
||||
self.description = "This tool allows you to execute Go code."
|
||||
|
||||
def execute(self, codes: str, safety=False) -> str:
|
||||
"""
|
||||
|
@ -15,6 +15,8 @@ class JavaInterpreter(Tools):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tag = "java"
|
||||
self.name = "Java Interpreter"
|
||||
self.description = "This tool allows you to execute Java code."
|
||||
|
||||
def execute(self, codes: str, safety=False) -> str:
|
||||
"""
|
||||
|
@ -16,6 +16,8 @@ class PyInterpreter(Tools):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tag = "python"
|
||||
self.name = "Python Interpreter"
|
||||
self.description = "This tool allows the agent to execute python code."
|
||||
|
||||
def execute(self, codes:str, safety = False) -> str:
|
||||
"""
|
||||
|
@ -15,6 +15,8 @@ class FileFinder(Tools):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tag = "file_finder"
|
||||
self.name = "File Finder"
|
||||
self.description = "Finds files in the current directory and returns their information."
|
||||
|
||||
def read_file(self, file_path: str) -> str:
|
||||
"""
|
||||
|
@ -16,6 +16,8 @@ class FlightSearch(Tools):
|
||||
"""
|
||||
super().__init__()
|
||||
self.tag = "flight_search"
|
||||
self.name = "Flight Search"
|
||||
self.description = "Search for flight information using a flight number via AviationStack API."
|
||||
self.api_key = None
|
||||
self.api_key = api_key or os.getenv("AVIATIONSTACK_API_KEY")
|
||||
|
||||
@ -24,7 +26,7 @@ class FlightSearch(Tools):
|
||||
return "Error: No AviationStack API key provided."
|
||||
|
||||
for block in blocks:
|
||||
flight_number = block.strip()
|
||||
flight_number = block.strip().lower().replace('\n', '')
|
||||
if not flight_number:
|
||||
return "Error: No flight number provided."
|
||||
|
||||
|
@ -3,11 +3,10 @@ import requests
|
||||
from urllib.parse import urljoin
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
class MCP_finder(Tools):
|
||||
"""
|
||||
@ -15,7 +14,9 @@ class MCP_finder(Tools):
|
||||
"""
|
||||
def __init__(self, api_key: str = None):
|
||||
super().__init__()
|
||||
self.tag = "mcp"
|
||||
self.tag = "mcp_finder"
|
||||
self.name = "MCP Finder"
|
||||
self.description = "Find MCP servers and their tools"
|
||||
self.base_url = "https://registry.smithery.ai"
|
||||
self.headers = {
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
@ -61,11 +62,7 @@ class MCP_finder(Tools):
|
||||
for mcp in mcps.get("servers", []):
|
||||
name = mcp.get("qualifiedName", "")
|
||||
if query.lower() in name.lower():
|
||||
details = {
|
||||
"name": name,
|
||||
"description": mcp.get("description", "No description available"),
|
||||
"params": mcp.get("connections", [])
|
||||
}
|
||||
details = self.get_mcp_server_details(name)
|
||||
matching_mcp.append(details)
|
||||
return matching_mcp
|
||||
|
||||
@ -79,7 +76,7 @@ class MCP_finder(Tools):
|
||||
try:
|
||||
matching_mcp_infos = self.find_mcp_servers(block_clean)
|
||||
except requests.exceptions.RequestException as e:
|
||||
output += "Connection failed. Is the API in environement?\n"
|
||||
output += "Connection failed. Is the API key in environement?\n"
|
||||
continue
|
||||
except Exception as e:
|
||||
output += f"Error: {str(e)}\n"
|
||||
@ -88,10 +85,12 @@ class MCP_finder(Tools):
|
||||
output += f"Error: No MCP server found for query '{block}'\n"
|
||||
continue
|
||||
for mcp_infos in matching_mcp_infos:
|
||||
output += f"Name: {mcp_infos['name']}\n"
|
||||
output += f"Description: {mcp_infos['description']}\n"
|
||||
output += f"Params: {', '.join(mcp_infos['params'])}\n"
|
||||
output += "-------\n"
|
||||
if mcp_infos['tools'] is None:
|
||||
continue
|
||||
output += f"Name: {mcp_infos['displayName']}\n"
|
||||
output += f"Usage name: {mcp_infos['qualifiedName']}\n"
|
||||
output += f"Tools: {mcp_infos['tools']}"
|
||||
output += "\n-------\n"
|
||||
return output.strip()
|
||||
|
||||
def execution_failure_check(self, output: str) -> bool:
|
||||
@ -107,13 +106,16 @@ class MCP_finder(Tools):
|
||||
Not really needed for this tool (use return of execute() directly)
|
||||
"""
|
||||
if not output:
|
||||
return "No output generated."
|
||||
return output.strip()
|
||||
raise ValueError("No output to interpret.")
|
||||
return f"""
|
||||
The following MCPs were found:
|
||||
{output}
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
api_key = os.getenv("MCP_FINDER")
|
||||
tool = MCP_finder(api_key)
|
||||
result = tool.execute(["""
|
||||
news
|
||||
stock
|
||||
"""], False)
|
||||
print(result)
|
@ -14,6 +14,8 @@ class searxSearch(Tools):
|
||||
"""
|
||||
super().__init__()
|
||||
self.tag = "web_search"
|
||||
self.name = "searxSearch"
|
||||
self.description = "A tool for searching a SearxNG for web search"
|
||||
self.base_url = base_url or os.getenv("SEARXNG_BASE_URL") # Requires a SearxNG base URL
|
||||
self.user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36"
|
||||
self.paywall_keywords = [
|
||||
|
@ -33,6 +33,8 @@ class Tools():
|
||||
"""
|
||||
def __init__(self):
|
||||
self.tag = "undefined"
|
||||
self.name = "undefined"
|
||||
self.description = "undefined"
|
||||
self.client = None
|
||||
self.messages = []
|
||||
self.logger = Logger("tools.log")
|
||||
|
Loading…
x
Reference in New Issue
Block a user