feat: support mcp settings

This commit is contained in:
He Tao
2025-04-23 16:00:01 +08:00
parent dae036f583
commit 0cf859b393
11 changed files with 147 additions and 27 deletions

View File

@@ -9,8 +9,16 @@ from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.runnables import RunnableConfig
from langchain_core.tools import tool
from langgraph.types import Command, interrupt
from langchain_mcp_adapters.client import MultiServerMCPClient
from src.agents.agents import coder_agent, research_agent, create_agent
from src.tools import (
crawl_tool,
web_search_tool,
python_repl_tool,
)
from src.agents.agents import coder_agent, research_agent
from src.config.agents import AGENT_LLM_MAP
from src.config.configuration import Configuration
from src.llms.llm import get_llm_by_type
@@ -171,7 +179,7 @@ def reporter_node(state: State):
for observation in observations:
invoke_messages.append(
HumanMessage(
content=f"Below is some observations for the user query:\n\n{observation}",
content=f"Below are some observations for the research task:\n\n{observation}",
name="observation",
)
)
@@ -203,7 +211,7 @@ def research_team_node(
return Command(goto="planner")
def _execute_agent_step(
async def _execute_agent_step(
state: State, agent, agent_name: str
) -> Command[Literal["research_team"]]:
"""Helper function to execute a step using the specified agent."""
@@ -236,7 +244,7 @@ def _execute_agent_step(
)
# Invoke the agent
result = agent.invoke(input=agent_input)
result = await agent.ainvoke(input=agent_input)
# Process the result
response_content = result["messages"][-1].content
@@ -260,13 +268,84 @@ def _execute_agent_step(
)
def researcher_node(state: State) -> Command[Literal["research_team"]]:
async def _setup_and_execute_agent_step(
state: State,
config: RunnableConfig,
agent_type: str,
default_agent,
default_tools: list,
) -> Command[Literal["research_team"]]:
"""Helper function to set up an agent with appropriate tools and execute a step.
This function handles the common logic for both researcher_node and coder_node:
1. Configures MCP servers and tools based on agent type
2. Creates an agent with the appropriate tools or uses the default agent
3. Executes the agent on the current step
Args:
state: The current state
config: The runnable config
agent_type: The type of agent ("researcher" or "coder")
default_agent: The default agent to use if no MCP servers are configured
default_tools: The default tools to add to the agent
Returns:
Command to update state and go to research_team
"""
configurable = Configuration.from_runnable_config(config)
mcp_servers = {}
enabled_tools = set()
# Extract MCP server configuration for this agent type
if configurable.mcp_settings:
for server_name, server_config in configurable.mcp_settings["servers"].items():
if (
server_config["enabled_tools"]
and agent_type in server_config["add_to_agents"]
):
mcp_servers[server_name] = {
k: v
for k, v in server_config.items()
if k in ("transport", "command", "args", "url", "env")
}
enabled_tools.update(server_config["enabled_tools"])
# Create and execute agent with MCP tools if available
if mcp_servers:
async with MultiServerMCPClient(mcp_servers) as client:
loaded_tools = [
tool for tool in client.get_tools() if tool.name in enabled_tools
] + default_tools
agent = create_agent(agent_type, agent_type, loaded_tools, agent_type)
return await _execute_agent_step(state, agent, agent_type)
else:
# Use default agent if no MCP servers are configured
return await _execute_agent_step(state, default_agent, agent_type)
async def researcher_node(
state: State, config: RunnableConfig
) -> Command[Literal["research_team"]]:
"""Researcher node that do research"""
logger.info("Researcher node is researching.")
return _execute_agent_step(state, research_agent, "researcher")
return await _setup_and_execute_agent_step(
state,
config,
"researcher",
research_agent,
[web_search_tool, crawl_tool],
)
def coder_node(state: State) -> Command[Literal["research_team"]]:
async def coder_node(
state: State, config: RunnableConfig
) -> Command[Literal["research_team"]]:
"""Coder node that do code analysis."""
logger.info("Coder node is coding.")
return _execute_agent_step(state, coder_agent, "coder")
return await _setup_and_execute_agent_step(
state,
config,
"coder",
coder_agent,
[python_repl_tool],
)