import asyncio
import os
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import HumanMessage
SPECIALISTS = {
"contacts": [
"contacts_get-contacts", "contacts_get-contact",
"contacts_create-contact", "contacts_update-contact",
"contacts_add-tags", "contacts_remove-tags",
],
"conversations": [
"conversations_search-conversation",
"conversations_get-messages",
"conversations_send-a-new-message",
],
"opportunities": [
"opportunities_search-opportunity",
"opportunities_get-pipelines",
"opportunities_get-opportunity",
"opportunities_update-opportunity",
],
}
async def run_multi_agent(user_message: str):
async with MultiServerMCPClient(
{
"hoopai": {
"transport": "streamable_http",
"url": "https://services.leadconnectorhq.com/mcp/",
"headers": {
"Authorization": f"Bearer {os.environ['HOOPAI_API_KEY']}",
"locationId": os.environ["HOOPAI_LOCATION_ID"],
},
}
}
) as client:
all_tools = client.get_tools()
model = ChatAnthropic(model="claude-sonnet-4-6")
# Build specialist agents
agents = {}
for name, allowed in SPECIALISTS.items():
tools = [t for t in all_tools if t.name in allowed]
agents[name] = create_react_agent(model, tools)
# Router decides which specialist to use
router_tools = [t for t in all_tools if t.name == "locations_get-location"]
router = create_react_agent(model, router_tools, state_modifier=(
"You are a router. Respond with only the specialist name: "
"contacts, conversations, or opportunities."
))
route_result = await router.ainvoke(
{"messages": [HumanMessage(content=f"Route this: {user_message}")]}
)
specialist_name = route_result["messages"][-1].content.strip().lower()
agent = agents.get(specialist_name, agents["contacts"])
result = await agent.ainvoke(
{"messages": [HumanMessage(content=user_message)]}
)
return result["messages"][-1].content
result = asyncio.run(run_multi_agent("Find all contacts tagged as 'New Lead' added this week"))
print(result)