mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 06:15:43 +00:00
Merge pull request #882 from ximot/feature/open-dashboard-tool
feat: Add open_dashboard MCP tool for on-demand dashboard opening
This commit is contained in:
5 files changed
+90
-31
No files matched your search
@@ -28,6 +28,7 @@ Note that in most configurations, only a subset of these tools will be enabled s
|
||||
* `list_dir`: Lists files and directories in the given directory (optionally with recursion).
|
||||
* `list_memories`: Lists memories in Serena's project-specific memory store.
|
||||
* `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
|
||||
* `open_dashboard`: Opens the Serena web dashboard in the default web browser.
|
||||
* `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with th
|
||||
e necessary context).
|
||||
* `read_file`: Reads a file within the project directory.
|
||||
|
||||
@@ -15,8 +15,21 @@ Serena comes with built-in tools for monitoring and managing the current session
|
||||
* the **GUI tool** (disabled by default)
|
||||
|
||||
The GUI tool is a native application window which displays logs.
|
||||
It furthermore allows you to shut down the agent and to access the dashboard's URL (if it is running).
|
||||
|
||||
This is mainly supported on Windows, but it may also work on Linux; macOS is unsupported.
|
||||
|
||||
Both can be configured in Serena's [configuration](050_configuration) file (`serena_config.yml`).
|
||||
If enabled, they will automatically be opened as soon as the Serena agent/MCP server is started.
|
||||
For the dashboard, this can be disabled if desired (see below).
|
||||
|
||||
## Disabling Automatic Browser Opening
|
||||
|
||||
If you prefer not to have the dashboard open automatically (e.g., to avoid focus stealing), you can disable it
|
||||
by setting `web_dashboard_open_on_launch: False` in your `serena_config.yml`.
|
||||
|
||||
When automatic opening is disabled, you can still access the dashboard by:
|
||||
* asking the LLM to "open the Serena dashboard", which will open the dashboard in your default browser
|
||||
(the tool `open_dashboard` is enabled for this purpose, provided that the dashboard is active,
|
||||
not opened by default and the GUI tool, which can provide the URL, is not enabled)
|
||||
* navigating directly to the URL (see above)
|
||||
+49
-23
@@ -2,11 +2,10 @@
|
||||
The Serena Model Context Protocol (MCP) Server
|
||||
"""
|
||||
|
||||
import multiprocessing
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
import webbrowser
|
||||
from collections.abc import Callable
|
||||
from logging import Logger
|
||||
from typing import TYPE_CHECKING, Optional, TypeVar
|
||||
@@ -24,7 +23,7 @@ from serena.ls_manager import LanguageServerManager
|
||||
from serena.project import Project
|
||||
from serena.prompt_factory import SerenaPromptFactory
|
||||
from serena.task_executor import TaskExecutor
|
||||
from serena.tools import ActivateProjectTool, GetCurrentConfigTool, ReplaceContentTool, Tool, ToolMarker, ToolRegistry
|
||||
from serena.tools import ActivateProjectTool, GetCurrentConfigTool, OpenDashboardTool, ReplaceContentTool, Tool, ToolMarker, ToolRegistry
|
||||
from serena.util.gui import system_has_usable_display
|
||||
from serena.util.inspection import iter_subclasses
|
||||
from serena.util.logging import MemoryLogHandler
|
||||
@@ -189,6 +188,9 @@ class SerenaAgent:
|
||||
# project-specific instances, which will be initialized upon project activation
|
||||
self._active_project: Project | None = None
|
||||
|
||||
# dashboard URL (set when dashboard is started)
|
||||
self._dashboard_url: str | None = None
|
||||
|
||||
# adjust log level
|
||||
serena_log_level = self.serena_config.log_level
|
||||
if Logger.root.level != serena_log_level:
|
||||
@@ -247,8 +249,21 @@ class SerenaAgent:
|
||||
self._check_shell_settings()
|
||||
|
||||
# determine the base toolset defining the set of exposed tools (which e.g. the MCP shall see),
|
||||
# limited by the Serena config, the context (which is fixed for the session) and JetBrains mode
|
||||
tool_inclusion_definitions: list[ToolInclusionDefinition] = [self.serena_config, self._context]
|
||||
# determined by the
|
||||
# * dashboard availability/opening on launch
|
||||
# * Serena config,
|
||||
# * the context (which is fixed for the session)
|
||||
# * single-project mode reductions (if applicable)
|
||||
# * JetBrains mode
|
||||
tool_inclusion_definitions: list[ToolInclusionDefinition] = []
|
||||
if (
|
||||
self.serena_config.web_dashboard
|
||||
and not self.serena_config.web_dashboard_open_on_launch
|
||||
and not self.serena_config.gui_log_window_enabled
|
||||
):
|
||||
tool_inclusion_definitions.append(ToolInclusionDefinition(included_optional_tools=[OpenDashboardTool.get_name_from_cls()]))
|
||||
tool_inclusion_definitions.append(self.serena_config)
|
||||
tool_inclusion_definitions.append(self._context)
|
||||
if self._context.single_project:
|
||||
tool_inclusion_definitions.extend(self._single_project_context_tool_inclusion_definitions(project))
|
||||
if self.serena_config.language_backend == LanguageBackend.JETBRAINS:
|
||||
@@ -292,16 +307,10 @@ class SerenaAgent:
|
||||
if dashboard_host == "0.0.0.0":
|
||||
dashboard_host = "localhost"
|
||||
dashboard_url = f"http://{dashboard_host}:{port}/dashboard/index.html"
|
||||
self._dashboard_url = dashboard_url
|
||||
log.info("Serena web dashboard started at %s", dashboard_url)
|
||||
if self.serena_config.web_dashboard_open_on_launch:
|
||||
if not system_has_usable_display():
|
||||
log.warning("Not opening the Serena web dashboard automatically because no usable display was detected.")
|
||||
else:
|
||||
# open the dashboard URL in the default web browser (using a separate process to control
|
||||
# output redirection)
|
||||
process = multiprocessing.Process(target=self._open_dashboard, args=(dashboard_url,))
|
||||
process.start()
|
||||
process.join(timeout=1)
|
||||
self.open_dashboard()
|
||||
# inform the GUI window (if any)
|
||||
if self._gui_log_viewer is not None:
|
||||
self._gui_log_viewer.set_dashboard_url(dashboard_url)
|
||||
@@ -393,17 +402,34 @@ class SerenaAgent:
|
||||
log.debug(f"Recording tool usage for tool '{tool_name}'")
|
||||
self._tool_usage_stats.record_tool_usage(tool_name, input_str, output_str)
|
||||
|
||||
@staticmethod
|
||||
def _open_dashboard(url: str) -> None:
|
||||
# Redirect stdout and stderr file descriptors to /dev/null,
|
||||
# making sure that nothing can be written to stdout/stderr, even by subprocesses
|
||||
null_fd = os.open(os.devnull, os.O_WRONLY)
|
||||
os.dup2(null_fd, sys.stdout.fileno())
|
||||
os.dup2(null_fd, sys.stderr.fileno())
|
||||
os.close(null_fd)
|
||||
def get_dashboard_url(self) -> str | None:
|
||||
"""
|
||||
:return: the URL of the web dashboard, or None if the dashboard is not running
|
||||
"""
|
||||
return self._dashboard_url
|
||||
|
||||
# open the dashboard URL in the default web browser
|
||||
webbrowser.open(url)
|
||||
def open_dashboard(self) -> bool:
|
||||
"""
|
||||
Opens the Serena web dashboard in the default web browser.
|
||||
|
||||
:return: a message indicating success or failure
|
||||
"""
|
||||
if self._dashboard_url is None:
|
||||
raise Exception("Dashboard is not running.")
|
||||
|
||||
if not system_has_usable_display():
|
||||
log.warning("Not opening the Serena web dashboard because no usable display was detected.")
|
||||
return False
|
||||
|
||||
# Use a subprocess to avoid any output from webbrowser.open being written to stdout
|
||||
subprocess.Popen(
|
||||
[sys.executable, "-c", f"import webbrowser; webbrowser.open({self._dashboard_url!r})"],
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
start_new_session=True, # Detach from parent process
|
||||
)
|
||||
return True
|
||||
|
||||
def get_project_root(self) -> str:
|
||||
"""
|
||||
|
||||
@@ -10,9 +10,8 @@ language_backend: LSP
|
||||
gui_log_window: False
|
||||
# whether to open a graphical window with Serena's logs.
|
||||
# This is mainly supported on Windows and (partly) on Linux; not available on macOS.
|
||||
# If you want to see the logs in a web browser, use the `web_dashboard` option instead.
|
||||
# Limitations: doesn't seem to work with the community version of Claude Desktop for Linux
|
||||
# Might also cause problems with some MCP clients - if you have any issues, try disabling this
|
||||
# If you prefer a browser-based tool, use the `web_dashboard` option instead.
|
||||
# Further information: https://oraios.github.io/serena/02-usage/060_dashboard.html
|
||||
#
|
||||
# Being able to inspect logs is useful both for troubleshooting and for monitoring the tool calls,
|
||||
# especially when using the agno playground, since the tool calls are not always shown,
|
||||
@@ -26,17 +25,21 @@ gui_log_window: False
|
||||
|
||||
web_dashboard: True
|
||||
# whether to open the Serena web dashboard (which will be accessible through your web browser) that
|
||||
# shows Serena's current session logs - as an alternative to the GUI log window which
|
||||
# is supported on all platforms.
|
||||
# provides access to Serena's configuration and state as well as the current session logs.
|
||||
# The web dashboard is supported on all platforms.
|
||||
# Further information: https://oraios.github.io/serena/02-usage/060_dashboard.html
|
||||
|
||||
web_dashboard_listen_address: 127.0.0.1
|
||||
# The address where the web dashboard will listen on
|
||||
|
||||
web_dashboard_open_on_launch: True
|
||||
# whether to open a browser window with the web dashboard when Serena starts (provided that web_dashboard
|
||||
# is enabled). If set to False, you can still open the dashboard manually by navigating to
|
||||
# http://localhost:24282/dashboard/ in your web browser (24282 = 0x5EDA, SErena DAshboard).
|
||||
# If you have multiple instances running, a higher port will be used; try port 24283, 24284, etc.
|
||||
# is enabled).
|
||||
# If set to false, you can still open the dashboard manually by
|
||||
# a) telling the LLM to "open the dashboard" (provided that the open_dashboard tool is enabled) or by
|
||||
# b) manually navigating to http://localhost:24282/dashboard/ in your web browser (actual port
|
||||
# may be higher if you have multiple instances running; try ports 24283, 24284, etc.)
|
||||
# See also: https://oraios.github.io/serena/02-usage/060_dashboard.html
|
||||
|
||||
log_level: 20
|
||||
# the minimum log level for the GUI log window and the dashboard (10 = debug, 20 = info, 30 = warning, 40 = error)
|
||||
|
||||
@@ -2,6 +2,22 @@ from serena.config.context_mode import SerenaAgentMode
|
||||
from serena.tools import Tool, ToolMarkerDoesNotRequireActiveProject, ToolMarkerOptional
|
||||
|
||||
|
||||
class OpenDashboardTool(Tool, ToolMarkerOptional, ToolMarkerDoesNotRequireActiveProject):
|
||||
"""
|
||||
Opens the Serena web dashboard in the default web browser.
|
||||
The dashboard provides logs, session information, and tool usage statistics.
|
||||
"""
|
||||
|
||||
def apply(self) -> str:
|
||||
"""
|
||||
Opens the Serena web dashboard in the default web browser.
|
||||
"""
|
||||
if self.agent.open_dashboard():
|
||||
return f"Serena web dashboard has been opened in the user's default web browser: {self.agent.get_dashboard_url()}"
|
||||
else:
|
||||
return f"Serena web dashboard could not be opened automatically; tell the user to open it via {self.agent.get_dashboard_url()}"
|
||||
|
||||
|
||||
class ActivateProjectTool(Tool, ToolMarkerDoesNotRequireActiveProject):
|
||||
"""
|
||||
Activates a project based on the project name or path.
|
||||
|
||||
Reference in new issue
Block a user