From d91cc115a87869abdb39c8a3026691e5c504dc89 Mon Sep 17 00:00:00 2001 From: vga91 Date: Tue, 25 Nov 2025 17:48:40 +0100 Subject: [PATCH 1/3] added MCP example with strands agents --- mcp_neo4j_client.py | 51 +++++++++++ mcp_neo4j_client2.py | 16 ++++ mcp_neo4j_client3.py | 36 ++++++++ mcp_neo4j_mistral_example.py | 39 +++++++++ mcp_neo4j_mistral_example1.py | 52 +++++++++++ mcp_neo4j_mistral_example2.py | 62 +++++++++++++ mcp_neo4j_mistral_example3.py | 47 ++++++++++ mcp_neo4j_server-without-neo4j.py | 46 ++++++++++ mcp_neo4j_server.py | 117 +++++++++++++++++++++++++ mcp_neo4j_server1.py | 17 ++++ mcp_neo4j_server2.py | 22 +++++ mcp_neo4j_server3.py | 28 ++++++ mcp_neo4j_server4.py | 30 +++++++ mcp_neo4j_server5.py | 29 ++++++ mcp_neo4j_server6.py | 39 +++++++++ mcp_neo4j_server7.py | 59 +++++++++++++ mcp_neo4j_tool.py | 36 ++++++++ my_strands_agent_demo-without-neo4j.py | 45 ++++++++++ my_strands_agent_demo.py | 49 +++++++++++ my_strands_agent_demo1.py | 36 ++++++++ neo4j_tool.py | 20 +++++ 21 files changed, 876 insertions(+) create mode 100644 mcp_neo4j_client.py create mode 100644 mcp_neo4j_client2.py create mode 100644 mcp_neo4j_client3.py create mode 100644 mcp_neo4j_mistral_example.py create mode 100644 mcp_neo4j_mistral_example1.py create mode 100644 mcp_neo4j_mistral_example2.py create mode 100644 mcp_neo4j_mistral_example3.py create mode 100644 mcp_neo4j_server-without-neo4j.py create mode 100644 mcp_neo4j_server.py create mode 100644 mcp_neo4j_server1.py create mode 100644 mcp_neo4j_server2.py create mode 100644 mcp_neo4j_server3.py create mode 100644 mcp_neo4j_server4.py create mode 100644 mcp_neo4j_server5.py create mode 100644 mcp_neo4j_server6.py create mode 100644 mcp_neo4j_server7.py create mode 100644 mcp_neo4j_tool.py create mode 100644 my_strands_agent_demo-without-neo4j.py create mode 100644 my_strands_agent_demo.py create mode 100644 my_strands_agent_demo1.py create mode 100644 neo4j_tool.py diff --git a/mcp_neo4j_client.py b/mcp_neo4j_client.py new file mode 100644 index 0000000..a318076 --- /dev/null +++ b/mcp_neo4j_client.py @@ -0,0 +1,51 @@ +# mcp_client_example_mistral.py + +from mcp.client.streamable_http import streamablehttp_client +from strands import Agent +from strands.tools.mcp.mcp_client import MCPClient + +# IMPORT MODELLO MISTRAL +from strands.models.mistral import MistralModel +import os +MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY") + +def create_streamable_http_transport(): + # L’URL deve essere quello del tuo server FastMCP + return streamablehttp_client("http://localhost:8000/mcp/") + + +def main(): + # 1) Crea client MCP + streamable_http_mcp_client = MCPClient(create_streamable_http_transport) + + with streamable_http_mcp_client: + # 2) Lista tool MCP + tools = streamable_http_mcp_client.list_tools_sync() + print("TOOLS disponibili:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) + + # 3) Crea l'agente con Mistral + agent = Agent( + tools=tools, + model=MistralModel( + api_key=MISTRAL_API_KEY, + model_id="mistral-small-latest", + temperature=0.7, + max_tokens=200, + ), + ) + + # 4) Esegui domanda tramite agente + response = agent("What is 125 plus 375?") + print("Risposta agente:", response) + + # 5) Oppure invoca il tool direttamente + result = streamable_http_mcp_client.call_tool_sync( + tool_use_id="tool-1", + name="neo4j_query", + arguments={"x": 125, "y": 375}, + ) + print("Risultato calcolatore:", result["content"][0]["text"]) + + +if __name__ == "__main__": + main() diff --git a/mcp_neo4j_client2.py b/mcp_neo4j_client2.py new file mode 100644 index 0000000..8200055 --- /dev/null +++ b/mcp_neo4j_client2.py @@ -0,0 +1,16 @@ +from mcp.client.streamable_http import streamablehttp_client +from mcp.client import MCPClient + +def create_transport(): + return streamablehttp_client("http://localhost:8000/mcp") + +if __name__ == "__main__": + client = MCPClient(create_transport) + with client: + tools = client.list_tools_sync() + print("TOOLS disponibili dal server MCP:", [t.name for t in tools]) + + # Esegui una query di test su Neo4j + query = "MATCH (n) RETURN n LIMIT 5" + result = client.call_sync("neo4j_query", query) + print("RISULTATO QUERY:\n", result) diff --git a/mcp_neo4j_client3.py b/mcp_neo4j_client3.py new file mode 100644 index 0000000..80d940e --- /dev/null +++ b/mcp_neo4j_client3.py @@ -0,0 +1,36 @@ +# mcp_client_example.py + +from mcp.client.streamable_http import streamablehttp_client +from strands import Agent +from strands.tools.mcp.mcp_client import MCPClient + +def create_streamable_http_transport(): + # Nota: l'URL deve corrispondere a quello usato dal tuo server FastMCP + return streamablehttp_client("http://localhost:8000/mcp/") + +def main(): + # Costruisci il client MCP di Strands + streamable_http_mcp_client = MCPClient(create_streamable_http_transport) + + # Usa il client in un context manager + with streamable_http_mcp_client: + tools = streamable_http_mcp_client.list_tools_sync() + print("TOOLS disponibili:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) + + # Crea l'agente Strands con quegli strumenti + agent = Agent(tools=tools) + + # Chiedi qualcosa all'agente che usa il tool "add" + response = agent("What is 125 plus 375?") + print("Risposta agente:", response) + + # Oppure invoca direttamente il tool + result = streamable_http_mcp_client.call_tool_sync( + tool_use_id="tool-1", + name="add", + arguments={"x": 125, "y": 375} + ) + print("Risultato calcolatore:", result["content"][0]["text"]) + +if __name__ == "__main__": + main() diff --git a/mcp_neo4j_mistral_example.py b/mcp_neo4j_mistral_example.py new file mode 100644 index 0000000..0d05252 --- /dev/null +++ b/mcp_neo4j_mistral_example.py @@ -0,0 +1,39 @@ +from strands import Agent +from mcp.client.streamable_http import streamablehttp_client +from strands.tools.mcp.mcp_client import MCPClient +from strands.models.mistral import MistralModel + +def create_streamable_http_transport(): + return streamablehttp_client("http://localhost:8000/mcp/") + +def main(): + mcp_client = MCPClient(create_streamable_http_transport) + + with mcp_client: + tools = mcp_client.list_tools_sync() + print("TOOLS disponibili:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) + + # Agente Mistral con prompt system che forza l'uso del tool + agent = Agent( + tools=tools, + model=MistralModel( + api_key="aDHQXyGQcIP4uNSdI6vc24YA8vjkLr22", + model_id="mistral-small-latest", + max_tokens=200, + temperature=0, + stream=False + ), + system_prompt=( + "Se ricevi un'operazione da eseguire, non calcolarla da solo. " + "Usa sempre il tool Neo4j `neo4j_query` per ottenere il risultato. " + "Non scrivere numeri direttamente, sempre tramite il tool." + ) + ) + + # Esempio: somma tramite query Neo4j + query = "RETURN 125 + 375 AS result" + response = agent(f"Esegui la query: {query}") + print("Risposta agente:", response) + +if __name__ == "__main__": + main() diff --git a/mcp_neo4j_mistral_example1.py b/mcp_neo4j_mistral_example1.py new file mode 100644 index 0000000..cd05641 --- /dev/null +++ b/mcp_neo4j_mistral_example1.py @@ -0,0 +1,52 @@ +# mcp_neo4j_mistral_example.py + +from mcp.client.streamable_http import streamablehttp_client +from strands import Agent +from strands.tools.mcp.mcp_client import MCPClient +from strands.models.mistral import MistralModel + +def create_streamable_http_transport(): + # URL del tuo server FastMCP + return streamablehttp_client("http://localhost:8000/mcp/") + +def main(): + # 1️⃣ Costruisci il client MCP + streamable_http_mcp_client = MCPClient(create_streamable_http_transport) + + with streamable_http_mcp_client: + # 2️⃣ Lista dei tool disponibili + tools = streamable_http_mcp_client.list_tools_sync() + print("TOOLS disponibili:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) + + # 3️⃣ Crea l'agente con modello Mistral + agent = Agent( + tools=tools, + model=MistralModel( + api_key="aDHQXyGQcIP4uNSdI6vc24YA8vjkLr22", # <--- metti la tua chiave + model_id="mistral-small-latest", + max_tokens=200, + temperature=0.7, + ) + ) + + # 4️⃣ Esempio: Mistral usa il tool neo4j_query per calcolare 125+375 + # Nota: il prompt deve istruire l'agente a usare il tool + prompt = """ + Compute 125 + 375 using the neo4j_query tool. + Only use the tool, do not calculate in your head. + """ + + response = agent(prompt) + print("Risposta agente:", response) + + # 5️⃣ Alternativa: chiamata diretta al tool (manuale) + cypher_query = "RETURN 125 + 375 AS result" + result = streamable_http_mcp_client.call_tool_sync( + tool_use_id="tool-1", + name="neo4j_query", + arguments={"query": cypher_query} + ) + print("Risultato Neo4j:", result["content"][0]["text"]) + +if __name__ == "__main__": + main() diff --git a/mcp_neo4j_mistral_example2.py b/mcp_neo4j_mistral_example2.py new file mode 100644 index 0000000..f29f80d --- /dev/null +++ b/mcp_neo4j_mistral_example2.py @@ -0,0 +1,62 @@ +# mcp_neo4j_mistral_example.py + +from mcp.client.streamable_http import streamablehttp_client +from strands import Agent +from strands.tools.mcp.mcp_client import MCPClient +from strands.models.mistral import MistralModel + + +def create_transport(): + # Transport per comunicare col server MCP locale + return streamablehttp_client("http://localhost:8000/mcp/") + + +def main(): + # 1️⃣ Configura client MCP + client = MCPClient(create_transport) + + with client: + # Lista tool disponibili + tools = client.list_tools_sync() + print("TOOLS disponibili:", [t.mcp_tool.name for t in tools]) + + # 2️⃣ Crea l'agente Mistral + # Nota: aggiungiamo al prompt istruzioni per usare solo i tool + agent = Agent( + tools=tools, + model=MistralModel( + api_key="aDHQXyGQcIP4uNSdI6vc24YA8vjkLr22", # metti la tua chiave + model_id="mistral-small-latest", + max_tokens=200, + temperature=0.0, + system_prompt=( + "You are a Neo4j assistant. " + "You MUST always use the 'neo4j_query' tool to execute queries. " + "Never answer arithmetic yourself." + ) + ) + ) + + # 3️⃣ Prompt all'agente + prompt = """ + You must always use the 'neo4j_query' tool to execute any query. + Do not answer arithmetic yourself. + + Execute this query in Neo4j: RETURN 125 + 375 AS result + """ + + # Invocazione dell'agente + response = agent(prompt) + print("Risposta agente:", response) + + # 4️⃣ Chiamata diretta al tool Neo4j (solo per verifica) + neo4j_result = client.call_tool_sync( + tool_use_id="tool-1", + name="neo4j_query", + arguments={"query": "RETURN 125 + 375 AS result"} + ) + print("Risultato Neo4j:", neo4j_result) + + +if __name__ == "__main__": + main() diff --git a/mcp_neo4j_mistral_example3.py b/mcp_neo4j_mistral_example3.py new file mode 100644 index 0000000..b8c4433 --- /dev/null +++ b/mcp_neo4j_mistral_example3.py @@ -0,0 +1,47 @@ +from mcp.client.streamable_http import streamablehttp_client +from strands import Agent +from strands.tools.mcp.mcp_client import MCPClient +from strands.models.mistral import MistralModel + +def create_streamable_http_transport(): + return streamablehttp_client("http://localhost:8000/mcp/") + +def main(): + # 1) Costruisci il client MCP + streamable_http_mcp_client = MCPClient(create_streamable_http_transport) + + with streamable_http_mcp_client: + # 2) Lista tools disponibili + tools = streamable_http_mcp_client.list_tools_sync() + print("TOOLS disponibili:", [t.mcp_tool.name for t in tools]) + + # 3) Crea l'agente con Mistral + agent = Agent( + tools=tools, + model=MistralModel( + api_key="aDHQXyGQcIP4uNSdI6vc24YA8vjkLr22", + model_id="mistral-small-latest", + max_tokens=200, + temperature=0.7 + ) + ) + + # 4) Prompt strutturato: forza l'uso del tool + prompt = """ +You must always use the 'neo4j_query' tool to execute any query. +Do not calculate arithmetic yourself. +Query to execute: RETURN 125 + 375 AS result +""" + response = agent(prompt) + print("Risposta agente:", response) + + # 5) Chiamata diretta al tool (opzionale) + result = streamable_http_mcp_client.call_tool_sync( + tool_use_id="tool-1", + name="neo4j_query", + arguments={"query": "RETURN 125 + 375 AS result"} + ) + print("Risultato Neo4j:", result) + +if __name__ == "__main__": + main() diff --git a/mcp_neo4j_server-without-neo4j.py b/mcp_neo4j_server-without-neo4j.py new file mode 100644 index 0000000..520f4bb --- /dev/null +++ b/mcp_neo4j_server-without-neo4j.py @@ -0,0 +1,46 @@ +from strands import Agent +from strands.models.mistral import MistralModel +from strands.tools.mcp import MCPClient +import os + +# Import del client HTTP MCP (streamable) +try: + from mcp.client.streamable_http import streamablehttp_client +except ImportError: + # fallback se la versione mcp è differente + from mcp.client.http import http_client as streamablehttp_client + +MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY") + +def create_transport(): + # Qui indichi l'endpoint HTTP del tuo server MCP + # Assicurati che il percorso corrisponda a quello usato da FastMCP (es. /mcp) + return streamablehttp_client("http://localhost:8000/mcp") + +mcp_client = MCPClient(create_transport) + +if __name__ == "__main__": + with mcp_client: + tools = mcp_client.list_tools_sync() + print("TOOLS disponibili dal server MCP:", [t.name for t in tools]) + + # Crea l’agente Strands con Mistral + model = MistralModel( + api_key=MISTRAL_API_KEY, # metti la tua chiave Mistral + model_id="mistral-small-latest", + max_tokens=200, + temperature=0.7, + ) + + agent = Agent(model=model, tools=tools) + + # Prompt: chiedi di eseguire una query tramite il tool Neo4j + prompt = "Esegui questa query Neo4j e dimmi il risultato: `MATCH (n) RETURN n LIMIT 5`" + result = agent(prompt) + + # Stampa il risultato restituito dall'agente + # a seconda della versione di Strands, può essere result.output o str(result) + try: + print("RISULTATO:", result.output) + except AttributeError: + print("RISULTATO:", result) diff --git a/mcp_neo4j_server.py b/mcp_neo4j_server.py new file mode 100644 index 0000000..1bcbd60 --- /dev/null +++ b/mcp_neo4j_server.py @@ -0,0 +1,117 @@ +from mcp.server import FastMCP +from neo4j import GraphDatabase +from neo4j.exceptions import Neo4jError +import os + +# Configurazione Neo4j +NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") +NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") +NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") + +# Crea il server MCP +mcp = FastMCP("Neo4j MCP Server") + +@mcp.tool(description="Esegui una query Neo4j, ritorna il risultato e registra la query") +def neo4j_query(query: str): + try: + with GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) as driver: + print(f"[LOG] Tentativo di connessione a Neo4j con URI: {NEO4J_URI}, utente: {NEO4J_USER}") + + try: + with driver.session() as session: + # 1️⃣ Lettura query + def run_main_query(tx): + print(f"[LOG] Esecuzione query principale: {query}") + result = tx.run(query) + records = [record.data() for record in result] # ✅ qui dentro + print(f"[LOG] Risultati query: {records}") + return records + + records = session.execute_read(run_main_query) + + session.run( + "CREATE (q:ExecutedQuery) SET q.executedQuery = $query RETURN q", + parameters={"query": query} + ).single() + + print("[LOG] Query eseguita e registrata con successo.") + return records + + except Neo4jError as e: + print(f"[ERRORE] Durante l'esecuzione della query: {e}") + return {"error": str(e)} + + # finally: + # # driver.close() + # print("[LOG] Connessione Neo4j chiusa.") + # # 2️⃣ Scrittura nodo + # # def create_query_node(tx): + # # tx.run("CREATE (q:ExecutedQuery {query: $query})", query=query).consume() + # # print(f"[LOG] Nodo registrato per la query: {query}") + + # try: + # with driver.session() as session: + # # create node and set the query property using a parameter + # session.run( + # "CREATE (q:ExecutedQuery) SET q.query = $query RETURN q", + # parameters={"query": query} + # ).single() + + # print("[LOG] Query eseguita e registrata con successo.") + # # return records + + # except Neo4jError as e: + # print(f"[ERRORE] Durante l'esecuzione della query: {e}") + # return {"error": str(e)} + + # finally: + # # driver.close() + # print("[LOG] Connessione Neo4j chiusa.") + # driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) + + + # try: + # # Verifica connessione + # try: + # with driver.session() as session: + # session.run("RETURN 1").single() + # print("[LOG] Connessione a Neo4j stabilita con successo.") + # except Neo4jError as e: + # print(f"[ERRORE] Connessione a Neo4j fallita: {e}") + # return {"error": str(e)} + + # with driver.session() as session: + + # # Esegui query principale in lettura + # def run_main_query(tx): + # print(f"[LOG] Esecuzione query principale: {query}") + # return tx.run(query) + + # result = session.execute_read(run_main_query) + # records = [record.data() for record in result] + # print(f"[LOG] Risultati query: {records}") + + # # Registra la query come nodo in scrittura + # def create_query_node(tx): + # tx.run("CREATE (q:ExecutedQuery {query: $query})", query=query) + # print(f"[LOG] Nodo registrato per la query: {query}") + + # session.execute_write(create_query_node) + + # print("[LOG] Query eseguita e registrata con successo.") + # return records + + # except Neo4jError as e: + # print(f"[ERRORE] Durante l'esecuzione della query: {e}") + # return {"error": str(e)} + + # finally: + # driver.close() + # print("[LOG] Connessione Neo4j chiusa.") + except Neo4jError as e: + print(f"[ERRORE] Durante l'esecuzione della query: {e}") + return {"error": str(e)} + +if __name__ == "__main__": + print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") + mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_server1.py b/mcp_neo4j_server1.py new file mode 100644 index 0000000..3ed6552 --- /dev/null +++ b/mcp_neo4j_server1.py @@ -0,0 +1,17 @@ +# mcp_neo4j_server.py +import asyncio +from strands.tools.mcp import MCPServer +from neo4j_tool import MCPNeo4jTool + +async def main(): + server = MCPServer() + + # Registra Neo4jTool + neo4j_tool = MCPNeo4jTool(uri="bolt://localhost:7687", user="neo4j", password="password") + server.register_tool(neo4j_tool) + + print("MCP Neo4j Server pronto con tool 'neo4j_tool'...") + await server.start(host="0.0.0.0", port=8000) + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/mcp_neo4j_server2.py b/mcp_neo4j_server2.py new file mode 100644 index 0000000..d012821 --- /dev/null +++ b/mcp_neo4j_server2.py @@ -0,0 +1,22 @@ +from strands.tools.mcp.mcp_client import MCPClient +from mcp.server.streamable_http import StreamableHTTPMCPServer +from mcp_neo4j_tool import MCPNeo4jTool + +# --- Configurazione Neo4j --- +NEO4J_URI = "bolt://localhost:7687" +NEO4J_USER = "neo4j" +NEO4J_PASSWORD = "password" + +# --- Inizializza il tool Neo4j --- +neo4j_tool = MCPNeo4jTool("neo4j_tool", NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD) + +# --- Crea server MCP HTTP --- +server = StreamableHTTPMCPServer( + host="0.0.0.0", + port=8000, + tools=[neo4j_tool] # esponiamo il tool Neo4j +) + +if __name__ == "__main__": + print("MCP Neo4j Server in avvio su http://localhost:8000/mcp …") + server.run() diff --git a/mcp_neo4j_server3.py b/mcp_neo4j_server3.py new file mode 100644 index 0000000..06b457d --- /dev/null +++ b/mcp_neo4j_server3.py @@ -0,0 +1,28 @@ +from mcp.server import MCPServer, MCPTool +from neo4j import GraphDatabase +import os + +# Configurazione Neo4j +NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") +NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") +NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "test") + +# Tool MCP per eseguire query Neo4j +class Neo4jQueryTool(MCPTool): + name = "neo4j_query" + + def run(self, query: str): + driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) + try: + with driver.session() as session: + result = session.run(query) + # Convertiamo i record in lista di dict + return [record.data() for record in result] + finally: + driver.close() + +if __name__ == "__main__": + # Avvio MCP server HTTP + server = MCPServer(host="0.0.0.0", port=8000, tools=[Neo4jQueryTool()]) + print("MCP Neo4j server running at http://localhost:8000/mcp") + server.start() diff --git a/mcp_neo4j_server4.py b/mcp_neo4j_server4.py new file mode 100644 index 0000000..69a8643 --- /dev/null +++ b/mcp_neo4j_server4.py @@ -0,0 +1,30 @@ +from mcp.server import FastMCP +from neo4j import GraphDatabase +import os + +# Configurazione Neo4j +NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") +NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") +NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") + +# Crea il server MCP +mcp = FastMCP("Neo4j MCP Server") + +@mcp.tool(description="Esegui una query Neo4j e ritorna il risultato") +def neo4j_query(query: str): + """ + Esegue la query Neo4j passata come stringa e ritorna il risultato come lista di dizionari. + """ + driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) + try: + with driver.session() as session: + print(f"Eseguendo query: {query}") + result = session.run(query) + return [record.data() for record in result] + finally: + driver.close() + +# Avvia il server con streamable HTTP (compatibile col client Strands) +if __name__ == "__main__": + print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") + mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_server5.py b/mcp_neo4j_server5.py new file mode 100644 index 0000000..cbbcf66 --- /dev/null +++ b/mcp_neo4j_server5.py @@ -0,0 +1,29 @@ +from mcp.server import FastMCP +from neo4j import GraphDatabase +import os + +# Configurazione Neo4j +NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") +NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") +NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") + +# Crea il server MCP +mcp = FastMCP("Neo4j MCP Server") + +@mcp.tool(description="Esegui una query Neo4j e ritorna il risultato") +def neo4j_query(query: str): + """ + Esegue la query Neo4j passata come stringa e ritorna il risultato come lista di dizionari. + """ + driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) + try: + with driver.session() as session: + print(f"Eseguendo query: {query}") # ← qui vedrai il log + result = session.run(query) + return [record.data() for record in result] + finally: + driver.close() + +if __name__ == "__main__": + print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") + mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_server6.py b/mcp_neo4j_server6.py new file mode 100644 index 0000000..ab95919 --- /dev/null +++ b/mcp_neo4j_server6.py @@ -0,0 +1,39 @@ +from mcp.server import FastMCP +from neo4j import GraphDatabase +import os + +# Configurazione Neo4j +NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") +NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") +NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") + +# Crea il server MCP +mcp = FastMCP("Neo4j MCP Server") + +@mcp.tool(description="Esegui una query Neo4j e ritorna il risultato") +def neo4j_query(query: str): + driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) + print("NEO4J_URI", "NEO4J_USER", "NEO4J_PASSWORD") + print(NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD) + try: + with driver.session() as session: + print(f"Eseguendo query: {query}") + + # 1️⃣ Esegui la query principale (lettura) + result = session.execute_read(query) + records = [record.data() for record in result] + + # 2️⃣ Crea un nodo per registrare la query eseguita usando una write transaction + def create_query_node(tx): + tx.run("CREATE (q:ExecutedQuery {query: $query})", query=query) + session.execute_write(create_query_node) + + print("Query eseguita e registrata con successo.") + return records + finally: + driver.close() + +# Avvia il server con streamable HTTP (compatibile col client Strands) +if __name__ == "__main__": + print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") + mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_server7.py b/mcp_neo4j_server7.py new file mode 100644 index 0000000..2ab05f1 --- /dev/null +++ b/mcp_neo4j_server7.py @@ -0,0 +1,59 @@ +from mcp.server import FastMCP +from neo4j import GraphDatabase +from neo4j.exceptions import Neo4jError +import os + +# Configurazione Neo4j +NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") +NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") +NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") + +# Crea il server MCP +mcp = FastMCP("Neo4j MCP Server") + +@mcp.tool(description="Esegui una query Neo4j, ritorna il risultato e registra la query") +def neo4j_query(query: str): + try: + with GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) as driver: + print(f"[LOG] Tentativo di connessione a Neo4j con URI: {NEO4J_URI}, utente: {NEO4J_USER}") + + try: + with driver.session() as session: + # 1️⃣ Lettura query + def run_main_query(tx): + print(f"[LOG] Esecuzione query principale: {query}") + result = tx.run(query) + records = [record.data() for record in result] # ✅ qui dentro + print(f"[LOG] Risultati query: {records}") + return records + + records = session.execute_read(run_main_query) + return records + + except Neo4jError as e: + print(f"[ERRORE] Durante l'esecuzione della query: {e}") + return {"error": str(e)} + + + try: + with driver.session() as session: + # create node and set the query property using a parameter + session.run( + "CREATE (q:ExecutedQuery) SET q.query = $query RETURN q", + parameters={"query": query} + ).single() + + print("[LOG] Query eseguita e registrata con successo.") + # return records + + except Neo4jError as e: + print(f"[ERRORE] Durante l'esecuzione della query: {e}") + return {"error": str(e)} + + except Neo4jError as e: + print(f"[ERRORE] Durante l'esecuzione della query: {e}") + return {"error": str(e)} + +if __name__ == "__main__": + print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") + mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_tool.py b/mcp_neo4j_tool.py new file mode 100644 index 0000000..feb7617 --- /dev/null +++ b/mcp_neo4j_tool.py @@ -0,0 +1,36 @@ +from strands.types.tools import AgentTool +from neo4j import GraphDatabase +from datetime import timedelta +from strands.tools.mcp.mcp_client import MCPClient, MCPToolResult + +class MCPNeo4jTool(AgentTool): + """Tool MCP per eseguire query Neo4j reali.""" + + def __init__(self, name: str, uri: str, user: str, password: str): + super().__init__(name=name) + self.driver = GraphDatabase.driver(uri, auth=(user, password)) + + def call(self, arguments: dict, read_timeout_seconds: timedelta | None = None) -> MCPToolResult: + query = arguments.get("query") + if not query: + return MCPToolResult( + status="error", + toolUseId=arguments.get("toolUseId", "unknown"), + content=[{"text": "Missing 'query' argument"}] + ) + + try: + with self.driver.session() as session: + result = session.run(query) + records = [dict(r) for r in result] + return MCPToolResult( + status="success", + toolUseId=arguments.get("toolUseId", "neo4j_tool"), + content=[{"text": str(records)}] + ) + except Exception as e: + return MCPToolResult( + status="error", + toolUseId=arguments.get("toolUseId", "neo4j_tool"), + content=[{"text": f"Neo4j query failed: {str(e)}"}] + ) diff --git a/my_strands_agent_demo-without-neo4j.py b/my_strands_agent_demo-without-neo4j.py new file mode 100644 index 0000000..e57da5c --- /dev/null +++ b/my_strands_agent_demo-without-neo4j.py @@ -0,0 +1,45 @@ +from strands import Agent +from strands.models.mistral import MistralModel +from strands.tools.mcp.mcp_client import MCPClient +import os +MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY") + +# IMPORT del client HTTP fallback fornito dal pacchetto MCP +try: + from mcp.client.streamable_http import streamablehttp_client +except ImportError: + raise ImportError("streamablehttp_client non trovato. Controlla l'installazione del pacchetto MCP.") + +# Factory per creare il trasporto MCP HTTP +def create_streamable_http_transport(): + return streamablehttp_client("http://localhost:8000/mcp/") # URL del tuo server MCP + +# --- MCPClient --- # +mcp_client = MCPClient(create_streamable_http_transport) + +# --- Main --- # +if __name__ == "__main__": + with mcp_client: + # Recupera i tool disponibili dal server MCP + tools = mcp_client.list_tools_sync() + print("TOOLS disponibili:", [t.mcp_tool.name for t in tools]) + + # Crea l'agente con Mistral e i tool MCP + agent = Agent( + model=MistralModel( + api_key=MISTRAL_API_KEY, + model_id="mistral-large-latest", + max_tokens=300, + temperature=0.7, + ), + tools=tools + ) + + # Esempio: query Neo4j via tool MCP + question = "MATCH (p:Person) RETURN count(p) AS c" + result = agent(question) + try: + print("RISULTATO:", result.output) + except AttributeError: + # fallback se l'oggetto result non ha output + print("RISULTATO:", result) diff --git a/my_strands_agent_demo.py b/my_strands_agent_demo.py new file mode 100644 index 0000000..9ecd8e5 --- /dev/null +++ b/my_strands_agent_demo.py @@ -0,0 +1,49 @@ +from strands import Agent +from strands.models.mistral import MistralModel +from strands.tools.mcp.mcp_client import MCPClient +from mcp.client.streamable_http import streamablehttp_client +from mcp_neo4j_tool import MCPNeo4jTool + +# --- Configura il trasporto MCP (HTTP) --- +def create_transport(): + return streamablehttp_client("http://localhost:8000/mcp") # MCP server endpoint + +mcp_client = MCPClient(create_transport) + +# --- Configura Neo4j --- +NEO4J_URI = "bolt://localhost:7687" +NEO4J_USER = "neo4j" +NEO4J_PASSWORD = "password" + +neo4j_tool = MCPNeo4jTool("neo4j_tool", NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD) + +if __name__ == "__main__": + with mcp_client: + # Puoi aggiungere tool custom al client MCP + tools = mcp_client.list_tools_sync() + tools.append(neo4j_tool) # Aggiungi il tool Neo4j + + print("TOOLS disponibili:", [t.name for t in tools]) + + # --- Crea l'agente con Mistral --- + model = MistralModel( + api_key="LA_TUA_MISTRAL_API_KEY", + model_id="mistral-small-latest", + max_tokens=200, + temperature=0.7, + ) + + agent = Agent(model=model, tools=tools) + + # --- Prompt con query Neo4j reale --- + prompt = { + "tool": "neo4j_tool", + "arguments": {"query": "MATCH (n) RETURN n LIMIT 5"} + } + + result = agent(prompt) + + try: + print("RISULTATO:", result.output) + except AttributeError: + print("RISULTATO:", result) diff --git a/my_strands_agent_demo1.py b/my_strands_agent_demo1.py new file mode 100644 index 0000000..dcdee0c --- /dev/null +++ b/my_strands_agent_demo1.py @@ -0,0 +1,36 @@ +# my_strands_agent_demo.py +from strands import Agent +from strands.models.mistral import MistralModel +from strands.tools.mcp.mcp_client import MCPClient +from mcp.client.streamable_http import streamablehttp_client + +# Transport MCP via HTTP +def create_transport(): + return streamablehttp_client("http://localhost:8000/mcp/") + +mcp_client = MCPClient(create_transport) + +if __name__ == "__main__": + with mcp_client: + # Lista dei tool MCP + tools = mcp_client.list_tools_sync() + print("TOOLS DISPONIBILI:", [t.mcp_tool.name for t in tools]) + + # Trova il tool Neo4j + neo4j_tool = next(t for t in tools if t.mcp_tool.name == "neo4j_tool") + + # Agent MistralModel + agent = Agent( + model=MistralModel( + api_key="LA_TUA_MISTRAL_API_KEY", + model_id="mistral-large-latest", + max_tokens=300, + temperature=0.7, + ), + tools=tools + ) + + # Esempio query Neo4j tramite tool MCP + query = "MATCH (p:Person) RETURN count(p) AS c" + result = neo4j_tool.run({"query": query}) + print("RISULTATO NEO4J:", result) diff --git a/neo4j_tool.py b/neo4j_tool.py new file mode 100644 index 0000000..1590184 --- /dev/null +++ b/neo4j_tool.py @@ -0,0 +1,20 @@ +# neo4j_tool.py +from neo4j import GraphDatabase + +class MCPNeo4jTool: + """Tool MCP per eseguire query Neo4j""" + + def __init__(self, uri: str, user: str, password: str): + self.driver = GraphDatabase.driver(uri, auth=(user, password)) + self.name = "neo4j_tool" + + def run(self, input_data: dict): + """Esegue query Neo4j passata come input_data['query']""" + query = input_data.get("query") + if not query: + return {"error": "No query provided"} + + with self.driver.session() as session: + result = session.run(query) + rows = [record.data() for record in result] + return {"result": rows} From d880484d81804137b7e5474f5beced3dceb01f09 Mon Sep 17 00:00:00 2001 From: vga91 Date: Thu, 27 Nov 2025 09:45:47 +0100 Subject: [PATCH 2/3] added MCP example --- mcp_neo4j_client.py | 20 +-- mcp_neo4j_client2.py | 16 -- mcp_neo4j_client3.py | 36 ---- mcp_neo4j_mistral_example.py | 39 ----- mcp_neo4j_mistral_example1.py | 52 ------ mcp_neo4j_mistral_example2.py | 62 ------- mcp_neo4j_mistral_example3.py | 47 ------ mcp_neo4j_server-without-neo4j.py | 46 ----- mcp_neo4j_server.py | 93 ++--------- mcp_neo4j_server1.py | 17 -- mcp_neo4j_server2.py | 22 --- mcp_neo4j_server3.py | 28 ---- mcp_neo4j_server4.py | 30 ---- mcp_neo4j_server5.py | 29 ---- mcp_neo4j_server6.py | 39 ----- mcp_neo4j_server7.py | 59 ------- modules/genai-ecosystem/nav.adoc | 2 + .../pages/genai-frameworks.adoc | 1 + modules/genai-ecosystem/pages/index.adoc | 1 + .../pages/strands-agents-neo4j.adoc | 158 ++++++++++++++++++ my_strands_agent_demo-without-neo4j.py | 45 ----- my_strands_agent_demo.py | 49 ------ my_strands_agent_demo1.py | 36 ---- neo4j_tool.py | 4 +- 24 files changed, 187 insertions(+), 744 deletions(-) delete mode 100644 mcp_neo4j_client2.py delete mode 100644 mcp_neo4j_client3.py delete mode 100644 mcp_neo4j_mistral_example.py delete mode 100644 mcp_neo4j_mistral_example1.py delete mode 100644 mcp_neo4j_mistral_example2.py delete mode 100644 mcp_neo4j_mistral_example3.py delete mode 100644 mcp_neo4j_server-without-neo4j.py delete mode 100644 mcp_neo4j_server1.py delete mode 100644 mcp_neo4j_server2.py delete mode 100644 mcp_neo4j_server3.py delete mode 100644 mcp_neo4j_server4.py delete mode 100644 mcp_neo4j_server5.py delete mode 100644 mcp_neo4j_server6.py delete mode 100644 mcp_neo4j_server7.py create mode 100644 modules/genai-ecosystem/pages/strands-agents-neo4j.adoc delete mode 100644 my_strands_agent_demo-without-neo4j.py delete mode 100644 my_strands_agent_demo.py delete mode 100644 my_strands_agent_demo1.py diff --git a/mcp_neo4j_client.py b/mcp_neo4j_client.py index a318076..0f940a9 100644 --- a/mcp_neo4j_client.py +++ b/mcp_neo4j_client.py @@ -4,26 +4,26 @@ from strands import Agent from strands.tools.mcp.mcp_client import MCPClient -# IMPORT MODELLO MISTRAL +# IMPORT MISTRAL MODEL from strands.models.mistral import MistralModel import os MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY") def create_streamable_http_transport(): - # L’URL deve essere quello del tuo server FastMCP + # The URL must be the one of your FastMCP server return streamablehttp_client("http://localhost:8000/mcp/") def main(): - # 1) Crea client MCP + # 1) Create the MCP client streamable_http_mcp_client = MCPClient(create_streamable_http_transport) with streamable_http_mcp_client: - # 2) Lista tool MCP + # 2) List available MCP tools tools = streamable_http_mcp_client.list_tools_sync() - print("TOOLS disponibili:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) + print("Available TOOLS:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) - # 3) Crea l'agente con Mistral + # 3) Create the agent using Mistral agent = Agent( tools=tools, model=MistralModel( @@ -34,17 +34,17 @@ def main(): ), ) - # 4) Esegui domanda tramite agente + # 4) Ask a question through the agent response = agent("What is 125 plus 375?") - print("Risposta agente:", response) + print("Agent response:", response) - # 5) Oppure invoca il tool direttamente + # 5) Or directly call a tool result = streamable_http_mcp_client.call_tool_sync( tool_use_id="tool-1", name="neo4j_query", arguments={"x": 125, "y": 375}, ) - print("Risultato calcolatore:", result["content"][0]["text"]) + print("Calculator result:", result["content"][0]["text"]) if __name__ == "__main__": diff --git a/mcp_neo4j_client2.py b/mcp_neo4j_client2.py deleted file mode 100644 index 8200055..0000000 --- a/mcp_neo4j_client2.py +++ /dev/null @@ -1,16 +0,0 @@ -from mcp.client.streamable_http import streamablehttp_client -from mcp.client import MCPClient - -def create_transport(): - return streamablehttp_client("http://localhost:8000/mcp") - -if __name__ == "__main__": - client = MCPClient(create_transport) - with client: - tools = client.list_tools_sync() - print("TOOLS disponibili dal server MCP:", [t.name for t in tools]) - - # Esegui una query di test su Neo4j - query = "MATCH (n) RETURN n LIMIT 5" - result = client.call_sync("neo4j_query", query) - print("RISULTATO QUERY:\n", result) diff --git a/mcp_neo4j_client3.py b/mcp_neo4j_client3.py deleted file mode 100644 index 80d940e..0000000 --- a/mcp_neo4j_client3.py +++ /dev/null @@ -1,36 +0,0 @@ -# mcp_client_example.py - -from mcp.client.streamable_http import streamablehttp_client -from strands import Agent -from strands.tools.mcp.mcp_client import MCPClient - -def create_streamable_http_transport(): - # Nota: l'URL deve corrispondere a quello usato dal tuo server FastMCP - return streamablehttp_client("http://localhost:8000/mcp/") - -def main(): - # Costruisci il client MCP di Strands - streamable_http_mcp_client = MCPClient(create_streamable_http_transport) - - # Usa il client in un context manager - with streamable_http_mcp_client: - tools = streamable_http_mcp_client.list_tools_sync() - print("TOOLS disponibili:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) - - # Crea l'agente Strands con quegli strumenti - agent = Agent(tools=tools) - - # Chiedi qualcosa all'agente che usa il tool "add" - response = agent("What is 125 plus 375?") - print("Risposta agente:", response) - - # Oppure invoca direttamente il tool - result = streamable_http_mcp_client.call_tool_sync( - tool_use_id="tool-1", - name="add", - arguments={"x": 125, "y": 375} - ) - print("Risultato calcolatore:", result["content"][0]["text"]) - -if __name__ == "__main__": - main() diff --git a/mcp_neo4j_mistral_example.py b/mcp_neo4j_mistral_example.py deleted file mode 100644 index 0d05252..0000000 --- a/mcp_neo4j_mistral_example.py +++ /dev/null @@ -1,39 +0,0 @@ -from strands import Agent -from mcp.client.streamable_http import streamablehttp_client -from strands.tools.mcp.mcp_client import MCPClient -from strands.models.mistral import MistralModel - -def create_streamable_http_transport(): - return streamablehttp_client("http://localhost:8000/mcp/") - -def main(): - mcp_client = MCPClient(create_streamable_http_transport) - - with mcp_client: - tools = mcp_client.list_tools_sync() - print("TOOLS disponibili:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) - - # Agente Mistral con prompt system che forza l'uso del tool - agent = Agent( - tools=tools, - model=MistralModel( - api_key="aDHQXyGQcIP4uNSdI6vc24YA8vjkLr22", - model_id="mistral-small-latest", - max_tokens=200, - temperature=0, - stream=False - ), - system_prompt=( - "Se ricevi un'operazione da eseguire, non calcolarla da solo. " - "Usa sempre il tool Neo4j `neo4j_query` per ottenere il risultato. " - "Non scrivere numeri direttamente, sempre tramite il tool." - ) - ) - - # Esempio: somma tramite query Neo4j - query = "RETURN 125 + 375 AS result" - response = agent(f"Esegui la query: {query}") - print("Risposta agente:", response) - -if __name__ == "__main__": - main() diff --git a/mcp_neo4j_mistral_example1.py b/mcp_neo4j_mistral_example1.py deleted file mode 100644 index cd05641..0000000 --- a/mcp_neo4j_mistral_example1.py +++ /dev/null @@ -1,52 +0,0 @@ -# mcp_neo4j_mistral_example.py - -from mcp.client.streamable_http import streamablehttp_client -from strands import Agent -from strands.tools.mcp.mcp_client import MCPClient -from strands.models.mistral import MistralModel - -def create_streamable_http_transport(): - # URL del tuo server FastMCP - return streamablehttp_client("http://localhost:8000/mcp/") - -def main(): - # 1️⃣ Costruisci il client MCP - streamable_http_mcp_client = MCPClient(create_streamable_http_transport) - - with streamable_http_mcp_client: - # 2️⃣ Lista dei tool disponibili - tools = streamable_http_mcp_client.list_tools_sync() - print("TOOLS disponibili:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) - - # 3️⃣ Crea l'agente con modello Mistral - agent = Agent( - tools=tools, - model=MistralModel( - api_key="aDHQXyGQcIP4uNSdI6vc24YA8vjkLr22", # <--- metti la tua chiave - model_id="mistral-small-latest", - max_tokens=200, - temperature=0.7, - ) - ) - - # 4️⃣ Esempio: Mistral usa il tool neo4j_query per calcolare 125+375 - # Nota: il prompt deve istruire l'agente a usare il tool - prompt = """ - Compute 125 + 375 using the neo4j_query tool. - Only use the tool, do not calculate in your head. - """ - - response = agent(prompt) - print("Risposta agente:", response) - - # 5️⃣ Alternativa: chiamata diretta al tool (manuale) - cypher_query = "RETURN 125 + 375 AS result" - result = streamable_http_mcp_client.call_tool_sync( - tool_use_id="tool-1", - name="neo4j_query", - arguments={"query": cypher_query} - ) - print("Risultato Neo4j:", result["content"][0]["text"]) - -if __name__ == "__main__": - main() diff --git a/mcp_neo4j_mistral_example2.py b/mcp_neo4j_mistral_example2.py deleted file mode 100644 index f29f80d..0000000 --- a/mcp_neo4j_mistral_example2.py +++ /dev/null @@ -1,62 +0,0 @@ -# mcp_neo4j_mistral_example.py - -from mcp.client.streamable_http import streamablehttp_client -from strands import Agent -from strands.tools.mcp.mcp_client import MCPClient -from strands.models.mistral import MistralModel - - -def create_transport(): - # Transport per comunicare col server MCP locale - return streamablehttp_client("http://localhost:8000/mcp/") - - -def main(): - # 1️⃣ Configura client MCP - client = MCPClient(create_transport) - - with client: - # Lista tool disponibili - tools = client.list_tools_sync() - print("TOOLS disponibili:", [t.mcp_tool.name for t in tools]) - - # 2️⃣ Crea l'agente Mistral - # Nota: aggiungiamo al prompt istruzioni per usare solo i tool - agent = Agent( - tools=tools, - model=MistralModel( - api_key="aDHQXyGQcIP4uNSdI6vc24YA8vjkLr22", # metti la tua chiave - model_id="mistral-small-latest", - max_tokens=200, - temperature=0.0, - system_prompt=( - "You are a Neo4j assistant. " - "You MUST always use the 'neo4j_query' tool to execute queries. " - "Never answer arithmetic yourself." - ) - ) - ) - - # 3️⃣ Prompt all'agente - prompt = """ - You must always use the 'neo4j_query' tool to execute any query. - Do not answer arithmetic yourself. - - Execute this query in Neo4j: RETURN 125 + 375 AS result - """ - - # Invocazione dell'agente - response = agent(prompt) - print("Risposta agente:", response) - - # 4️⃣ Chiamata diretta al tool Neo4j (solo per verifica) - neo4j_result = client.call_tool_sync( - tool_use_id="tool-1", - name="neo4j_query", - arguments={"query": "RETURN 125 + 375 AS result"} - ) - print("Risultato Neo4j:", neo4j_result) - - -if __name__ == "__main__": - main() diff --git a/mcp_neo4j_mistral_example3.py b/mcp_neo4j_mistral_example3.py deleted file mode 100644 index b8c4433..0000000 --- a/mcp_neo4j_mistral_example3.py +++ /dev/null @@ -1,47 +0,0 @@ -from mcp.client.streamable_http import streamablehttp_client -from strands import Agent -from strands.tools.mcp.mcp_client import MCPClient -from strands.models.mistral import MistralModel - -def create_streamable_http_transport(): - return streamablehttp_client("http://localhost:8000/mcp/") - -def main(): - # 1) Costruisci il client MCP - streamable_http_mcp_client = MCPClient(create_streamable_http_transport) - - with streamable_http_mcp_client: - # 2) Lista tools disponibili - tools = streamable_http_mcp_client.list_tools_sync() - print("TOOLS disponibili:", [t.mcp_tool.name for t in tools]) - - # 3) Crea l'agente con Mistral - agent = Agent( - tools=tools, - model=MistralModel( - api_key="aDHQXyGQcIP4uNSdI6vc24YA8vjkLr22", - model_id="mistral-small-latest", - max_tokens=200, - temperature=0.7 - ) - ) - - # 4) Prompt strutturato: forza l'uso del tool - prompt = """ -You must always use the 'neo4j_query' tool to execute any query. -Do not calculate arithmetic yourself. -Query to execute: RETURN 125 + 375 AS result -""" - response = agent(prompt) - print("Risposta agente:", response) - - # 5) Chiamata diretta al tool (opzionale) - result = streamable_http_mcp_client.call_tool_sync( - tool_use_id="tool-1", - name="neo4j_query", - arguments={"query": "RETURN 125 + 375 AS result"} - ) - print("Risultato Neo4j:", result) - -if __name__ == "__main__": - main() diff --git a/mcp_neo4j_server-without-neo4j.py b/mcp_neo4j_server-without-neo4j.py deleted file mode 100644 index 520f4bb..0000000 --- a/mcp_neo4j_server-without-neo4j.py +++ /dev/null @@ -1,46 +0,0 @@ -from strands import Agent -from strands.models.mistral import MistralModel -from strands.tools.mcp import MCPClient -import os - -# Import del client HTTP MCP (streamable) -try: - from mcp.client.streamable_http import streamablehttp_client -except ImportError: - # fallback se la versione mcp è differente - from mcp.client.http import http_client as streamablehttp_client - -MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY") - -def create_transport(): - # Qui indichi l'endpoint HTTP del tuo server MCP - # Assicurati che il percorso corrisponda a quello usato da FastMCP (es. /mcp) - return streamablehttp_client("http://localhost:8000/mcp") - -mcp_client = MCPClient(create_transport) - -if __name__ == "__main__": - with mcp_client: - tools = mcp_client.list_tools_sync() - print("TOOLS disponibili dal server MCP:", [t.name for t in tools]) - - # Crea l’agente Strands con Mistral - model = MistralModel( - api_key=MISTRAL_API_KEY, # metti la tua chiave Mistral - model_id="mistral-small-latest", - max_tokens=200, - temperature=0.7, - ) - - agent = Agent(model=model, tools=tools) - - # Prompt: chiedi di eseguire una query tramite il tool Neo4j - prompt = "Esegui questa query Neo4j e dimmi il risultato: `MATCH (n) RETURN n LIMIT 5`" - result = agent(prompt) - - # Stampa il risultato restituito dall'agente - # a seconda della versione di Strands, può essere result.output o str(result) - try: - print("RISULTATO:", result.output) - except AttributeError: - print("RISULTATO:", result) diff --git a/mcp_neo4j_server.py b/mcp_neo4j_server.py index 1bcbd60..daa6c78 100644 --- a/mcp_neo4j_server.py +++ b/mcp_neo4j_server.py @@ -3,28 +3,28 @@ from neo4j.exceptions import Neo4jError import os -# Configurazione Neo4j +# Neo4j configuration NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") -# Crea il server MCP +# Create the MCP server mcp = FastMCP("Neo4j MCP Server") -@mcp.tool(description="Esegui una query Neo4j, ritorna il risultato e registra la query") +@mcp.tool(description="Execute a Neo4j query, return the result, and log the query") def neo4j_query(query: str): - try: + try: with GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) as driver: - print(f"[LOG] Tentativo di connessione a Neo4j con URI: {NEO4J_URI}, utente: {NEO4J_USER}") + print(f"[LOG] Attempting connection to Neo4j with URI: {NEO4J_URI}, user: {NEO4J_USER}") try: with driver.session() as session: - # 1️⃣ Lettura query + # 1️⃣ Read query def run_main_query(tx): - print(f"[LOG] Esecuzione query principale: {query}") + print(f"[LOG] Executing main query: {query}") result = tx.run(query) - records = [record.data() for record in result] # ✅ qui dentro - print(f"[LOG] Risultati query: {records}") + records = [record.data() for record in result] # ✅ here + print(f"[LOG] Query results: {records}") return records records = session.execute_read(run_main_query) @@ -34,84 +34,17 @@ def run_main_query(tx): parameters={"query": query} ).single() - print("[LOG] Query eseguita e registrata con successo.") + print("[LOG] Query executed and logged successfully.") return records except Neo4jError as e: - print(f"[ERRORE] Durante l'esecuzione della query: {e}") + print(f"[ERROR] Error executing query: {e}") return {"error": str(e)} - # finally: - # # driver.close() - # print("[LOG] Connessione Neo4j chiusa.") - # # 2️⃣ Scrittura nodo - # # def create_query_node(tx): - # # tx.run("CREATE (q:ExecutedQuery {query: $query})", query=query).consume() - # # print(f"[LOG] Nodo registrato per la query: {query}") - - # try: - # with driver.session() as session: - # # create node and set the query property using a parameter - # session.run( - # "CREATE (q:ExecutedQuery) SET q.query = $query RETURN q", - # parameters={"query": query} - # ).single() - - # print("[LOG] Query eseguita e registrata con successo.") - # # return records - - # except Neo4jError as e: - # print(f"[ERRORE] Durante l'esecuzione della query: {e}") - # return {"error": str(e)} - - # finally: - # # driver.close() - # print("[LOG] Connessione Neo4j chiusa.") - # driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) - - - # try: - # # Verifica connessione - # try: - # with driver.session() as session: - # session.run("RETURN 1").single() - # print("[LOG] Connessione a Neo4j stabilita con successo.") - # except Neo4jError as e: - # print(f"[ERRORE] Connessione a Neo4j fallita: {e}") - # return {"error": str(e)} - - # with driver.session() as session: - - # # Esegui query principale in lettura - # def run_main_query(tx): - # print(f"[LOG] Esecuzione query principale: {query}") - # return tx.run(query) - - # result = session.execute_read(run_main_query) - # records = [record.data() for record in result] - # print(f"[LOG] Risultati query: {records}") - - # # Registra la query come nodo in scrittura - # def create_query_node(tx): - # tx.run("CREATE (q:ExecutedQuery {query: $query})", query=query) - # print(f"[LOG] Nodo registrato per la query: {query}") - - # session.execute_write(create_query_node) - - # print("[LOG] Query eseguita e registrata con successo.") - # return records - - # except Neo4jError as e: - # print(f"[ERRORE] Durante l'esecuzione della query: {e}") - # return {"error": str(e)} - - # finally: - # driver.close() - # print("[LOG] Connessione Neo4j chiusa.") except Neo4jError as e: - print(f"[ERRORE] Durante l'esecuzione della query: {e}") + print(f"[ERROR] Error executing query: {e}") return {"error": str(e)} if __name__ == "__main__": - print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") + print("MCP Neo4j server running at http://localhost:8000/mcp") mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_server1.py b/mcp_neo4j_server1.py deleted file mode 100644 index 3ed6552..0000000 --- a/mcp_neo4j_server1.py +++ /dev/null @@ -1,17 +0,0 @@ -# mcp_neo4j_server.py -import asyncio -from strands.tools.mcp import MCPServer -from neo4j_tool import MCPNeo4jTool - -async def main(): - server = MCPServer() - - # Registra Neo4jTool - neo4j_tool = MCPNeo4jTool(uri="bolt://localhost:7687", user="neo4j", password="password") - server.register_tool(neo4j_tool) - - print("MCP Neo4j Server pronto con tool 'neo4j_tool'...") - await server.start(host="0.0.0.0", port=8000) - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/mcp_neo4j_server2.py b/mcp_neo4j_server2.py deleted file mode 100644 index d012821..0000000 --- a/mcp_neo4j_server2.py +++ /dev/null @@ -1,22 +0,0 @@ -from strands.tools.mcp.mcp_client import MCPClient -from mcp.server.streamable_http import StreamableHTTPMCPServer -from mcp_neo4j_tool import MCPNeo4jTool - -# --- Configurazione Neo4j --- -NEO4J_URI = "bolt://localhost:7687" -NEO4J_USER = "neo4j" -NEO4J_PASSWORD = "password" - -# --- Inizializza il tool Neo4j --- -neo4j_tool = MCPNeo4jTool("neo4j_tool", NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD) - -# --- Crea server MCP HTTP --- -server = StreamableHTTPMCPServer( - host="0.0.0.0", - port=8000, - tools=[neo4j_tool] # esponiamo il tool Neo4j -) - -if __name__ == "__main__": - print("MCP Neo4j Server in avvio su http://localhost:8000/mcp …") - server.run() diff --git a/mcp_neo4j_server3.py b/mcp_neo4j_server3.py deleted file mode 100644 index 06b457d..0000000 --- a/mcp_neo4j_server3.py +++ /dev/null @@ -1,28 +0,0 @@ -from mcp.server import MCPServer, MCPTool -from neo4j import GraphDatabase -import os - -# Configurazione Neo4j -NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") -NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") -NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "test") - -# Tool MCP per eseguire query Neo4j -class Neo4jQueryTool(MCPTool): - name = "neo4j_query" - - def run(self, query: str): - driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) - try: - with driver.session() as session: - result = session.run(query) - # Convertiamo i record in lista di dict - return [record.data() for record in result] - finally: - driver.close() - -if __name__ == "__main__": - # Avvio MCP server HTTP - server = MCPServer(host="0.0.0.0", port=8000, tools=[Neo4jQueryTool()]) - print("MCP Neo4j server running at http://localhost:8000/mcp") - server.start() diff --git a/mcp_neo4j_server4.py b/mcp_neo4j_server4.py deleted file mode 100644 index 69a8643..0000000 --- a/mcp_neo4j_server4.py +++ /dev/null @@ -1,30 +0,0 @@ -from mcp.server import FastMCP -from neo4j import GraphDatabase -import os - -# Configurazione Neo4j -NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") -NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") -NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") - -# Crea il server MCP -mcp = FastMCP("Neo4j MCP Server") - -@mcp.tool(description="Esegui una query Neo4j e ritorna il risultato") -def neo4j_query(query: str): - """ - Esegue la query Neo4j passata come stringa e ritorna il risultato come lista di dizionari. - """ - driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) - try: - with driver.session() as session: - print(f"Eseguendo query: {query}") - result = session.run(query) - return [record.data() for record in result] - finally: - driver.close() - -# Avvia il server con streamable HTTP (compatibile col client Strands) -if __name__ == "__main__": - print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") - mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_server5.py b/mcp_neo4j_server5.py deleted file mode 100644 index cbbcf66..0000000 --- a/mcp_neo4j_server5.py +++ /dev/null @@ -1,29 +0,0 @@ -from mcp.server import FastMCP -from neo4j import GraphDatabase -import os - -# Configurazione Neo4j -NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") -NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") -NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") - -# Crea il server MCP -mcp = FastMCP("Neo4j MCP Server") - -@mcp.tool(description="Esegui una query Neo4j e ritorna il risultato") -def neo4j_query(query: str): - """ - Esegue la query Neo4j passata come stringa e ritorna il risultato come lista di dizionari. - """ - driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) - try: - with driver.session() as session: - print(f"Eseguendo query: {query}") # ← qui vedrai il log - result = session.run(query) - return [record.data() for record in result] - finally: - driver.close() - -if __name__ == "__main__": - print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") - mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_server6.py b/mcp_neo4j_server6.py deleted file mode 100644 index ab95919..0000000 --- a/mcp_neo4j_server6.py +++ /dev/null @@ -1,39 +0,0 @@ -from mcp.server import FastMCP -from neo4j import GraphDatabase -import os - -# Configurazione Neo4j -NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") -NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") -NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") - -# Crea il server MCP -mcp = FastMCP("Neo4j MCP Server") - -@mcp.tool(description="Esegui una query Neo4j e ritorna il risultato") -def neo4j_query(query: str): - driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) - print("NEO4J_URI", "NEO4J_USER", "NEO4J_PASSWORD") - print(NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD) - try: - with driver.session() as session: - print(f"Eseguendo query: {query}") - - # 1️⃣ Esegui la query principale (lettura) - result = session.execute_read(query) - records = [record.data() for record in result] - - # 2️⃣ Crea un nodo per registrare la query eseguita usando una write transaction - def create_query_node(tx): - tx.run("CREATE (q:ExecutedQuery {query: $query})", query=query) - session.execute_write(create_query_node) - - print("Query eseguita e registrata con successo.") - return records - finally: - driver.close() - -# Avvia il server con streamable HTTP (compatibile col client Strands) -if __name__ == "__main__": - print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") - mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_server7.py b/mcp_neo4j_server7.py deleted file mode 100644 index 2ab05f1..0000000 --- a/mcp_neo4j_server7.py +++ /dev/null @@ -1,59 +0,0 @@ -from mcp.server import FastMCP -from neo4j import GraphDatabase -from neo4j.exceptions import Neo4jError -import os - -# Configurazione Neo4j -NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") -NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") -NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") - -# Crea il server MCP -mcp = FastMCP("Neo4j MCP Server") - -@mcp.tool(description="Esegui una query Neo4j, ritorna il risultato e registra la query") -def neo4j_query(query: str): - try: - with GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) as driver: - print(f"[LOG] Tentativo di connessione a Neo4j con URI: {NEO4J_URI}, utente: {NEO4J_USER}") - - try: - with driver.session() as session: - # 1️⃣ Lettura query - def run_main_query(tx): - print(f"[LOG] Esecuzione query principale: {query}") - result = tx.run(query) - records = [record.data() for record in result] # ✅ qui dentro - print(f"[LOG] Risultati query: {records}") - return records - - records = session.execute_read(run_main_query) - return records - - except Neo4jError as e: - print(f"[ERRORE] Durante l'esecuzione della query: {e}") - return {"error": str(e)} - - - try: - with driver.session() as session: - # create node and set the query property using a parameter - session.run( - "CREATE (q:ExecutedQuery) SET q.query = $query RETURN q", - parameters={"query": query} - ).single() - - print("[LOG] Query eseguita e registrata con successo.") - # return records - - except Neo4jError as e: - print(f"[ERRORE] Durante l'esecuzione della query: {e}") - return {"error": str(e)} - - except Neo4jError as e: - print(f"[ERRORE] Durante l'esecuzione della query: {e}") - return {"error": str(e)} - -if __name__ == "__main__": - print("MCP Neo4j server in esecuzione su http://localhost:8000/mcp") - mcp.run(transport="streamable-http") diff --git a/modules/genai-ecosystem/nav.adoc b/modules/genai-ecosystem/nav.adoc index 178628f..21e2165 100644 --- a/modules/genai-ecosystem/nav.adoc +++ b/modules/genai-ecosystem/nav.adoc @@ -28,3 +28,5 @@ // **** link:xxx[Documentation] **** xref:semantic-kernel.adoc[Semantic Kernel] // **** link:xxx[Documentation] +**** xref:strands-agents-neo4j[Strands Agents] +// **** link:xxx[Documentation] diff --git a/modules/genai-ecosystem/pages/genai-frameworks.adoc b/modules/genai-ecosystem/pages/genai-frameworks.adoc index 5b0d385..911b9e1 100644 --- a/modules/genai-ecosystem/pages/genai-frameworks.adoc +++ b/modules/genai-ecosystem/pages/genai-frameworks.adoc @@ -34,6 +34,7 @@ Neo4j and our community have contributed integrations to many of these framework * xref:langchain4j.adoc[LangChain4j] * xref:haystack.adoc[Haystack] * xref:semantic-kernel.adoc[Semantic Kernel] +* xref:strands-agents-neo4j.adoc[Strands Agents] * xref:dspy.adoc[DSPy] == GraphAcademy Courses diff --git a/modules/genai-ecosystem/pages/index.adoc b/modules/genai-ecosystem/pages/index.adoc index 1bd8dea..3011654 100644 --- a/modules/genai-ecosystem/pages/index.adoc +++ b/modules/genai-ecosystem/pages/index.adoc @@ -90,6 +90,7 @@ You can find overviews of these integrations in the pages of this section, as we * xref:langchain4j.adoc[LangChain4j] * xref:haystack.adoc[Haystack] * xref:semantic-kernel.adoc[Semantic Kernel] +* xref:strands-agents-neo4j.adoc[Strands Agents] * xref:dspy.adoc[DSPy] == Highlighted Articles diff --git a/modules/genai-ecosystem/pages/strands-agents-neo4j.adoc b/modules/genai-ecosystem/pages/strands-agents-neo4j.adoc new file mode 100644 index 0000000..0b9acf8 --- /dev/null +++ b/modules/genai-ecosystem/pages/strands-agents-neo4j.adoc @@ -0,0 +1,158 @@ += Strands AI Agents with MCP and Neo4j +:slug: strands-mcp-neo4j +:author: +:category: genai-ecosystem +:tags: strands, mcp, llm, neo4j +:page-pagination: +:page-product: strands-ai + +Integration of Neo4j graph database with Strands Agents. +Neo4j's graph capabilities can be exposed as MCP tools, allowing LLM-powered Strands Agents to query and modify the database via a standard protocol over HTTP or SSE. + +Two main examples are provided: + +* `mcp_neo4j_client.py` — calls Neo4j tools via a Strands Agent using MCP transport. +* `mcp_neo4j_server.py` — demonstrates a full MCP setup with a FastMCP server exposing Neo4j tools. + +== Installation + +[source,bash] +---- +pip install openai fastapi uvicorn neo4j +---- + +Start a Neo4j instance (local or cloud). + +== Usage + +1) Run the MCP server exposing Neo4j tools: + +[source,bash] +---- +python mcp_neo4j_server.py +---- + +2) Run the Strands Agent client connecting to the server: + +[source,bash] +---- +python mcp_neo4j_client.py +---- + +== Example: mcp_neo4j_server.py (FastMCP server exposing Neo4j tools) + +[source,python] +---- +from mcp.server import FastMCP +from neo4j import GraphDatabase +from neo4j.exceptions import Neo4jError +import os + +# Neo4j configuration +NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") +NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") +NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") + +# Create FastMCP server +mcp = FastMCP("Neo4j MCP Server") + +@mcp.tool(description="Execute a Neo4j query, return the result, and log it") +def neo4j_query(query: str): + try: + with GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) as driver: + print(f"[LOG] Connecting to Neo4j at {NEO4J_URI} with user {NEO4J_USER}") + try: + with driver.session() as session: + def run_main_query(tx): + print(f"[LOG] Executing query: {query}") + records = [record.data() for record in tx.run(query)] + print(f"[LOG] Query results: {records}") + return records + + records = session.execute_read(run_main_query) + + session.run( + "CREATE (q:ExecutedQuery) SET q.executedQuery = $query RETURN q", + parameters={"query": query} + ).single() + + print("[LOG] Query executed and logged successfully.") + return records + + except Neo4jError as e: + print(f"[ERROR] Query execution failed: {e}") + return {"error": str(e)} + except Neo4jError as e: + print(f"[ERROR] Connection failed: {e}") + return {"error": str(e)} + +if __name__ == "__main__": + print("MCP Neo4j server running at http://localhost:8000/mcp") + mcp.run(transport="streamable-http") +---- + +== Example: mcp_neo4j_client.py (Strands Agent using MCP) + +[source,python] +---- +from strands import Agent +from strands.tools.mcp.mcp_client import MCPClient +from mcp.client.streamable_http import streamablehttp_client + +def create_transport(): + return streamablehttp_client("http://localhost:8000/mcp/") + +def main(): + # 1) Create MCP client + client = MCPClient(create_transport) + + with client: + # 2) List available tools + tools = client.list_tools_sync() + print("Available tools:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) + + # 3) Create a Strands Agent using the Mistral model + from strands.models.mistral import MistralModel + import os + agent = Agent( + tools=tools, + model=MistralModel( + api_key=os.getenv("MISTRAL_API_KEY"), + model_id="mistral-small-latest", + temperature=0.7, + max_tokens=200 + ) + ) + + # 4) Ask a question through the agent + response = agent("What is 125 plus 375?") + print("Agent response:", response) + + # 5) Or directly call a tool + result = client.call_tool_sync( + tool_use_id="tool-1", + name="neo4j_query", + arguments={"x": 125, "y": 375} + ) + print("Calculator result:", result["content"][0]["text"]) + +if __name__ == "__main__": + main() +---- + +== Functionality Includes + +* `neo4j_query` — wraps Neo4j operations as an MCP tool +* FastMCP server exposing Neo4j tools +* Strands Agent using MCP transport to call tools +* LLM integration via Mistral model + +== Relevant Links +[cols="1,4"] +|=== +| icon:user[] Authors | https://github.com/vga91[Vincenzo Gallo^] +| icon:comments[] Community Support | https://community.neo4j.com/[Neo4j Online Community^] +| icon:github[] Integration | https://github.com/vga91/strands-mcp-neo4j[GitHub] +| icon:github[] Issues | https://github.com/vga91/strands-mcp-neo4j/issues +| icon:book[] Documentation | https://vga91.github.io/strands-mcp-neo4j/[Docs] +|=== diff --git a/my_strands_agent_demo-without-neo4j.py b/my_strands_agent_demo-without-neo4j.py deleted file mode 100644 index e57da5c..0000000 --- a/my_strands_agent_demo-without-neo4j.py +++ /dev/null @@ -1,45 +0,0 @@ -from strands import Agent -from strands.models.mistral import MistralModel -from strands.tools.mcp.mcp_client import MCPClient -import os -MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY") - -# IMPORT del client HTTP fallback fornito dal pacchetto MCP -try: - from mcp.client.streamable_http import streamablehttp_client -except ImportError: - raise ImportError("streamablehttp_client non trovato. Controlla l'installazione del pacchetto MCP.") - -# Factory per creare il trasporto MCP HTTP -def create_streamable_http_transport(): - return streamablehttp_client("http://localhost:8000/mcp/") # URL del tuo server MCP - -# --- MCPClient --- # -mcp_client = MCPClient(create_streamable_http_transport) - -# --- Main --- # -if __name__ == "__main__": - with mcp_client: - # Recupera i tool disponibili dal server MCP - tools = mcp_client.list_tools_sync() - print("TOOLS disponibili:", [t.mcp_tool.name for t in tools]) - - # Crea l'agente con Mistral e i tool MCP - agent = Agent( - model=MistralModel( - api_key=MISTRAL_API_KEY, - model_id="mistral-large-latest", - max_tokens=300, - temperature=0.7, - ), - tools=tools - ) - - # Esempio: query Neo4j via tool MCP - question = "MATCH (p:Person) RETURN count(p) AS c" - result = agent(question) - try: - print("RISULTATO:", result.output) - except AttributeError: - # fallback se l'oggetto result non ha output - print("RISULTATO:", result) diff --git a/my_strands_agent_demo.py b/my_strands_agent_demo.py deleted file mode 100644 index 9ecd8e5..0000000 --- a/my_strands_agent_demo.py +++ /dev/null @@ -1,49 +0,0 @@ -from strands import Agent -from strands.models.mistral import MistralModel -from strands.tools.mcp.mcp_client import MCPClient -from mcp.client.streamable_http import streamablehttp_client -from mcp_neo4j_tool import MCPNeo4jTool - -# --- Configura il trasporto MCP (HTTP) --- -def create_transport(): - return streamablehttp_client("http://localhost:8000/mcp") # MCP server endpoint - -mcp_client = MCPClient(create_transport) - -# --- Configura Neo4j --- -NEO4J_URI = "bolt://localhost:7687" -NEO4J_USER = "neo4j" -NEO4J_PASSWORD = "password" - -neo4j_tool = MCPNeo4jTool("neo4j_tool", NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD) - -if __name__ == "__main__": - with mcp_client: - # Puoi aggiungere tool custom al client MCP - tools = mcp_client.list_tools_sync() - tools.append(neo4j_tool) # Aggiungi il tool Neo4j - - print("TOOLS disponibili:", [t.name for t in tools]) - - # --- Crea l'agente con Mistral --- - model = MistralModel( - api_key="LA_TUA_MISTRAL_API_KEY", - model_id="mistral-small-latest", - max_tokens=200, - temperature=0.7, - ) - - agent = Agent(model=model, tools=tools) - - # --- Prompt con query Neo4j reale --- - prompt = { - "tool": "neo4j_tool", - "arguments": {"query": "MATCH (n) RETURN n LIMIT 5"} - } - - result = agent(prompt) - - try: - print("RISULTATO:", result.output) - except AttributeError: - print("RISULTATO:", result) diff --git a/my_strands_agent_demo1.py b/my_strands_agent_demo1.py deleted file mode 100644 index dcdee0c..0000000 --- a/my_strands_agent_demo1.py +++ /dev/null @@ -1,36 +0,0 @@ -# my_strands_agent_demo.py -from strands import Agent -from strands.models.mistral import MistralModel -from strands.tools.mcp.mcp_client import MCPClient -from mcp.client.streamable_http import streamablehttp_client - -# Transport MCP via HTTP -def create_transport(): - return streamablehttp_client("http://localhost:8000/mcp/") - -mcp_client = MCPClient(create_transport) - -if __name__ == "__main__": - with mcp_client: - # Lista dei tool MCP - tools = mcp_client.list_tools_sync() - print("TOOLS DISPONIBILI:", [t.mcp_tool.name for t in tools]) - - # Trova il tool Neo4j - neo4j_tool = next(t for t in tools if t.mcp_tool.name == "neo4j_tool") - - # Agent MistralModel - agent = Agent( - model=MistralModel( - api_key="LA_TUA_MISTRAL_API_KEY", - model_id="mistral-large-latest", - max_tokens=300, - temperature=0.7, - ), - tools=tools - ) - - # Esempio query Neo4j tramite tool MCP - query = "MATCH (p:Person) RETURN count(p) AS c" - result = neo4j_tool.run({"query": query}) - print("RISULTATO NEO4J:", result) diff --git a/neo4j_tool.py b/neo4j_tool.py index 1590184..308d874 100644 --- a/neo4j_tool.py +++ b/neo4j_tool.py @@ -2,14 +2,14 @@ from neo4j import GraphDatabase class MCPNeo4jTool: - """Tool MCP per eseguire query Neo4j""" + """MCP tool for executing Neo4j queries""" def __init__(self, uri: str, user: str, password: str): self.driver = GraphDatabase.driver(uri, auth=(user, password)) self.name = "neo4j_tool" def run(self, input_data: dict): - """Esegue query Neo4j passata come input_data['query']""" + """Executes the Neo4j query provided as input_data['query']""" query = input_data.get("query") if not query: return {"error": "No query provided"} From 6fb86cb8e32b1e3239769907bc1658b489ec05bb Mon Sep 17 00:00:00 2001 From: vga91 Date: Thu, 27 Nov 2025 09:52:34 +0100 Subject: [PATCH 3/3] cleanup --- mcp_neo4j_client.py | 51 --------------------------------------------- mcp_neo4j_server.py | 50 -------------------------------------------- mcp_neo4j_tool.py | 36 -------------------------------- neo4j_tool.py | 20 ------------------ 4 files changed, 157 deletions(-) delete mode 100644 mcp_neo4j_client.py delete mode 100644 mcp_neo4j_server.py delete mode 100644 mcp_neo4j_tool.py delete mode 100644 neo4j_tool.py diff --git a/mcp_neo4j_client.py b/mcp_neo4j_client.py deleted file mode 100644 index 0f940a9..0000000 --- a/mcp_neo4j_client.py +++ /dev/null @@ -1,51 +0,0 @@ -# mcp_client_example_mistral.py - -from mcp.client.streamable_http import streamablehttp_client -from strands import Agent -from strands.tools.mcp.mcp_client import MCPClient - -# IMPORT MISTRAL MODEL -from strands.models.mistral import MistralModel -import os -MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY") - -def create_streamable_http_transport(): - # The URL must be the one of your FastMCP server - return streamablehttp_client("http://localhost:8000/mcp/") - - -def main(): - # 1) Create the MCP client - streamable_http_mcp_client = MCPClient(create_streamable_http_transport) - - with streamable_http_mcp_client: - # 2) List available MCP tools - tools = streamable_http_mcp_client.list_tools_sync() - print("Available TOOLS:", [getattr(t, "name", t.mcp_tool.name) for t in tools]) - - # 3) Create the agent using Mistral - agent = Agent( - tools=tools, - model=MistralModel( - api_key=MISTRAL_API_KEY, - model_id="mistral-small-latest", - temperature=0.7, - max_tokens=200, - ), - ) - - # 4) Ask a question through the agent - response = agent("What is 125 plus 375?") - print("Agent response:", response) - - # 5) Or directly call a tool - result = streamable_http_mcp_client.call_tool_sync( - tool_use_id="tool-1", - name="neo4j_query", - arguments={"x": 125, "y": 375}, - ) - print("Calculator result:", result["content"][0]["text"]) - - -if __name__ == "__main__": - main() diff --git a/mcp_neo4j_server.py b/mcp_neo4j_server.py deleted file mode 100644 index daa6c78..0000000 --- a/mcp_neo4j_server.py +++ /dev/null @@ -1,50 +0,0 @@ -from mcp.server import FastMCP -from neo4j import GraphDatabase -from neo4j.exceptions import Neo4jError -import os - -# Neo4j configuration -NEO4J_URI = os.getenv("NEO4J_URI", "bolt://localhost:7687") -NEO4J_USER = os.getenv("NEO4J_USER", "neo4j") -NEO4J_PASSWORD = os.getenv("NEO4J_PASSWORD", "apoc12345") - -# Create the MCP server -mcp = FastMCP("Neo4j MCP Server") - -@mcp.tool(description="Execute a Neo4j query, return the result, and log the query") -def neo4j_query(query: str): - try: - with GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD)) as driver: - print(f"[LOG] Attempting connection to Neo4j with URI: {NEO4J_URI}, user: {NEO4J_USER}") - - try: - with driver.session() as session: - # 1️⃣ Read query - def run_main_query(tx): - print(f"[LOG] Executing main query: {query}") - result = tx.run(query) - records = [record.data() for record in result] # ✅ here - print(f"[LOG] Query results: {records}") - return records - - records = session.execute_read(run_main_query) - - session.run( - "CREATE (q:ExecutedQuery) SET q.executedQuery = $query RETURN q", - parameters={"query": query} - ).single() - - print("[LOG] Query executed and logged successfully.") - return records - - except Neo4jError as e: - print(f"[ERROR] Error executing query: {e}") - return {"error": str(e)} - - except Neo4jError as e: - print(f"[ERROR] Error executing query: {e}") - return {"error": str(e)} - -if __name__ == "__main__": - print("MCP Neo4j server running at http://localhost:8000/mcp") - mcp.run(transport="streamable-http") diff --git a/mcp_neo4j_tool.py b/mcp_neo4j_tool.py deleted file mode 100644 index feb7617..0000000 --- a/mcp_neo4j_tool.py +++ /dev/null @@ -1,36 +0,0 @@ -from strands.types.tools import AgentTool -from neo4j import GraphDatabase -from datetime import timedelta -from strands.tools.mcp.mcp_client import MCPClient, MCPToolResult - -class MCPNeo4jTool(AgentTool): - """Tool MCP per eseguire query Neo4j reali.""" - - def __init__(self, name: str, uri: str, user: str, password: str): - super().__init__(name=name) - self.driver = GraphDatabase.driver(uri, auth=(user, password)) - - def call(self, arguments: dict, read_timeout_seconds: timedelta | None = None) -> MCPToolResult: - query = arguments.get("query") - if not query: - return MCPToolResult( - status="error", - toolUseId=arguments.get("toolUseId", "unknown"), - content=[{"text": "Missing 'query' argument"}] - ) - - try: - with self.driver.session() as session: - result = session.run(query) - records = [dict(r) for r in result] - return MCPToolResult( - status="success", - toolUseId=arguments.get("toolUseId", "neo4j_tool"), - content=[{"text": str(records)}] - ) - except Exception as e: - return MCPToolResult( - status="error", - toolUseId=arguments.get("toolUseId", "neo4j_tool"), - content=[{"text": f"Neo4j query failed: {str(e)}"}] - ) diff --git a/neo4j_tool.py b/neo4j_tool.py deleted file mode 100644 index 308d874..0000000 --- a/neo4j_tool.py +++ /dev/null @@ -1,20 +0,0 @@ -# neo4j_tool.py -from neo4j import GraphDatabase - -class MCPNeo4jTool: - """MCP tool for executing Neo4j queries""" - - def __init__(self, uri: str, user: str, password: str): - self.driver = GraphDatabase.driver(uri, auth=(user, password)) - self.name = "neo4j_tool" - - def run(self, input_data: dict): - """Executes the Neo4j query provided as input_data['query']""" - query = input_data.get("query") - if not query: - return {"error": "No query provided"} - - with self.driver.session() as session: - result = session.run(query) - rows = [record.data() for record in result] - return {"result": rows}