2424from sensai .util import logging
2525from sensai .util .helper import mark_used
2626
27- from serena .agent import SerenaAgent , ToolInterface , create_serena_config , show_fatal_exception_safe
28- from serena .config import SerenaAgentContext , SerenaAgentMode
27+ from serena .agent import (
28+ ActivateProjectTool ,
29+ Project ,
30+ SerenaAgent ,
31+ ToolInterface ,
32+ ToolRegistry ,
33+ create_serena_config ,
34+ show_fatal_exception_safe ,
35+ )
36+ from serena .config import RegisteredContext , SerenaAgentContext , SerenaAgentMode
2937from serena .constants import DEFAULT_CONTEXT , DEFAULT_MODES
3038from serena .process_isolated_agent import (
3139 ProcessIsolatedDashboard ,
@@ -137,25 +145,48 @@ def create_mcp_server_and_agent(
137145 context_instance = SerenaAgentContext .load (context )
138146 modes_instances = [SerenaAgentMode .load (mode ) for mode in modes ]
139147
148+ is_ide_assistant = context_instance .name == RegisteredContext .IDE_ASSISTANT .value
149+
150+ project_instance : Project | None = None
140151 if project is not None :
141- log .info (f"Will use project at mcp server startup: { project } " )
152+ # Fail early if the project cannot be loaded
153+ log .info (f"Will activate project { project } at mcp server startup" )
154+ try :
155+ project_instance = Project .load (project )
156+ except Exception as e :
157+ log .error (f"Failed to load or generate project config for { project } : { e } " )
158+ raise
159+ else :
160+ log .warning ("No project passed at startup, you will have to activate a project yourself (by asking the agent to do so)." )
161+
162+ tools_excluded_in_this_session = context_instance .get_excluded_tool_classes ()
163+ if is_ide_assistant and project_instance is not None :
164+ tools_excluded_in_this_session .extend (project_instance .project_config .get_excluded_tool_classes ())
165+ # if a project has been loaded, it will be activated at startup and in ide-assistant context,
166+ # we assume that no other project will be activated in this session.
167+ # Therefore, we exclude the activate project tool
168+ tools_excluded_in_this_session .append (ActivateProjectTool )
169+ tool_names_excluded_in_this_session = {tool .get_name_from_cls () for tool in tools_excluded_in_this_session }
170+
171+ all_tool_names = set (ToolRegistry .get_tool_names ())
172+ tool_names_included_in_this_session = all_tool_names - tool_names_excluded_in_this_session
142173
143174 try :
175+ # Start agent and dashboard processes (the latter only if enabled)
176+ serena_dashboard_process = None
144177 serena_config = create_serena_config (
145178 enable_web_dashboard = enable_web_dashboard ,
146179 enable_gui_log_window = enable_gui_log_window ,
147180 log_level = log_level ,
148181 trace_lsp_communication = trace_lsp_communication ,
149182 tool_timeout = tool_timeout ,
150183 )
184+ if serena_config .web_dashboard :
185+ serena_dashboard_process = ProcessIsolatedDashboard (tool_names = sorted (tool_names_included_in_this_session ))
151186 serena_agent_process = ProcessIsolatedSerenaAgent (
152187 project = project , serena_config = serena_config , modes = modes_instances , context = context_instance
153188 )
154189
155- # Start process-isolated dashboard if enabled
156- serena_dashboard_process = None
157- if serena_config .web_dashboard :
158- serena_dashboard_process = ProcessIsolatedDashboard (tool_names = [])
159190 except Exception as e :
160191 show_fatal_exception_safe (e )
161192 raise
@@ -164,15 +195,14 @@ def update_tools() -> None:
164195 """Update the tools in the MCP server - adapted for process isolation."""
165196 nonlocal mcp , serena_agent_process
166197
167- # Get tool names from process-isolated agent
168- # Tools may change as a result of project activation.
198+ # Get tool names from agent
199+ # Tools may change as a result of project or mode activation.
169200 # NOTE: While we could pass updated tool information on to the MCP server via the callback, Claude Desktop does not,
170201 # unfortunately, query for changed tools. It only queries for changed resources and prompts regularly,
171- # so we need to register all tools at startup, unfortunately.
172- tool_names = serena_agent_process .get_exposed_tool_names ()
202+ # so we need to register all potentially active tools at startup, unfortunately.
173203 if mcp is not None :
174204 mcp ._tool_manager ._tools = {}
175- for tool_name in tool_names :
205+ for tool_name in tool_names_included_in_this_session :
176206 process_isolated_tool = ProcessIsolatedTool (process_agent = serena_agent_process , tool_name = tool_name )
177207 mcp_tool = make_tool (process_isolated_tool )
178208 mcp ._tool_manager ._tools [tool_name ] = mcp_tool
0 commit comments