From 18f8661770b6e60624ab80669f5ced77d3767652 Mon Sep 17 00:00:00 2001 From: Tim O'Farrell Date: Fri, 8 Aug 2025 12:05:44 -0600 Subject: [PATCH] feat: add mcp_shttp_servers override to conversation initialization (#10171) Co-authored-by: openhands --- openhands/core/config/mcp_config.py | 9 +++++++++ .../server/routes/manage_conversations.py | 3 +++ .../server/services/conversation_service.py | 5 +++++ openhands/server/session/session.py | 20 ++++++++++++++----- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/openhands/core/config/mcp_config.py b/openhands/core/config/mcp_config.py index 7e96d426c7..4fa2d9673f 100644 --- a/openhands/core/config/mcp_config.py +++ b/openhands/core/config/mcp_config.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import re import shlex @@ -302,6 +304,13 @@ class MCPConfig(BaseModel): raise ValueError(f'Invalid MCP configuration: {e}') return mcp_mapping + def merge(self, other: MCPConfig): + return MCPConfig( + sse_servers=self.sse_servers + other.sse_servers, + stdio_servers=self.stdio_servers + other.stdio_servers, + shttp_servers=self.shttp_servers + other.shttp_servers, + ) + class OpenHandsMCPConfig: @staticmethod diff --git a/openhands/server/routes/manage_conversations.py b/openhands/server/routes/manage_conversations.py index 776f8e52a1..4d5dbc077d 100644 --- a/openhands/server/routes/manage_conversations.py +++ b/openhands/server/routes/manage_conversations.py @@ -10,6 +10,7 @@ from jinja2 import Environment, FileSystemLoader from pydantic import BaseModel, ConfigDict, Field from openhands.core.config.llm_config import LLMConfig +from openhands.core.config.mcp_config import MCPConfig from openhands.core.logger import openhands_logger as logger from openhands.events.action import ( ChangeAgentStateAction, @@ -87,6 +88,7 @@ class InitSessionRequest(BaseModel): suggested_task: SuggestedTask | None = None create_microagent: CreateMicroagent | None = None conversation_instructions: str | None = None + mcp_config: MCPConfig | None = None # Only nested runtimes require the ability to specify a conversation id, and it could be a security risk if os.getenv('ALLOW_SET_CONVERSATION_ID', '0') == '1': conversation_id: str = Field(default_factory=lambda: uuid.uuid4().hex) @@ -178,6 +180,7 @@ async def new_conversation( conversation_instructions=conversation_instructions, git_provider=git_provider, conversation_id=conversation_id, + mcp_config=data.mcp_config, ) return ConversationResponse( diff --git a/openhands/server/services/conversation_service.py b/openhands/server/services/conversation_service.py index 0866a7807a..7e8b68ec51 100644 --- a/openhands/server/services/conversation_service.py +++ b/openhands/server/services/conversation_service.py @@ -2,6 +2,7 @@ import uuid from types import MappingProxyType from typing import Any +from openhands.core.config.mcp_config import MCPConfig from openhands.core.logger import openhands_logger as logger from openhands.events.action.message import MessageAction from openhands.experiments.experiment_manager import ExperimentManagerImpl @@ -44,6 +45,7 @@ async def create_new_conversation( attach_convo_id: bool = False, git_provider: ProviderType | None = None, conversation_id: str | None = None, + mcp_config: MCPConfig | None = None, ) -> AgentLoopInfo: logger.info( 'Creating conversation', @@ -82,6 +84,9 @@ async def create_new_conversation( session_init_args['selected_branch'] = selected_branch session_init_args['git_provider'] = git_provider session_init_args['conversation_instructions'] = conversation_instructions + if mcp_config: + session_init_args['mcp_config'] = mcp_config + conversation_init_data = ConversationInitData(**session_init_args) logger.info('Loading conversation store') diff --git a/openhands/server/session/session.py b/openhands/server/session/session.py index ab0408163a..5f2836322e 100644 --- a/openhands/server/session/session.py +++ b/openhands/server/session/session.py @@ -124,10 +124,12 @@ class Session: ) # Set Git user configuration if provided in settings - if hasattr(settings, 'git_user_name') and settings.git_user_name: - self.config.git_user_name = settings.git_user_name - if hasattr(settings, 'git_user_email') and settings.git_user_email: - self.config.git_user_email = settings.git_user_email + git_user_name = getattr(settings, 'git_user_name', None) + if git_user_name is not None: + self.config.git_user_name = git_user_name + git_user_email = getattr(settings, 'git_user_email', None) + if git_user_email is not None: + self.config.git_user_email = git_user_email max_iterations = settings.max_iterations or self.config.max_iterations # Prioritize settings over config for max_budget_per_task @@ -152,6 +154,14 @@ class Session: self.logger.debug( f'MCP configuration before setup - self.config.mcp_config: {self.config.mcp}' ) + + # Check if settings has custom mcp_config + mcp_config = getattr(settings, 'mcp_config', None) + if mcp_config is not None: + # Use the provided MCP SHTTP servers instead of default setup + self.config.mcp = self.config.mcp.merge(mcp_config) + self.logger.debug(f'Merged custom MCP Config: {mcp_config}') + # Add OpenHands' MCP server by default openhands_mcp_server, openhands_mcp_stdio_servers = ( OpenHandsMCPConfigImpl.create_default_mcp_server_config( @@ -163,7 +173,7 @@ class Session: self.config.mcp.shttp_servers.append(openhands_mcp_server) self.logger.debug('Added default MCP HTTP server to config') - self.config.mcp.stdio_servers.extend(openhands_mcp_stdio_servers) + self.config.mcp.stdio_servers.extend(openhands_mcp_stdio_servers) self.logger.debug( f'MCP configuration after setup - self.config.mcp: {self.config.mcp}'