diff --git a/.gitignore b/.gitignore index a05922aa..a8137335 100644 --- a/.gitignore +++ b/.gitignore @@ -200,4 +200,8 @@ app_data.db # Don't commit the evaluation data *.evalset.json -.adk/ \ No newline at end of file +.adk/ + + +run-with-google-adk/libs/markdown +run-with-google-adk/libs/markdown-3.8.2.dist-info \ No newline at end of file diff --git a/run-with-google-adk/Makefile b/run-with-google-adk/Makefile index d9cdeb8c..ad3d63f3 100644 --- a/run-with-google-adk/Makefile +++ b/run-with-google-adk/Makefile @@ -1,11 +1,7 @@ # Makefile for ADK Runbooks project # -# Environment file -ifneq (,$(wildcard ./agents/google_mcp_security_agent/.env)) - include ./agents/google_mcp_security_agent/.env - export -endif +# Environment file is now loaded by the env_manager.py script # Python executable (use activated venv if available) PYTHON := python3 @@ -24,13 +20,14 @@ MANAGE_AGENTS := $(PYTHON) scripts/manage_agents.py ENV_FILE_PATH := agents/google_mcp_security_agent/.env ENV_MANAGER := $(PYTHON) scripts/env_manager.py -.PHONY: help env-check env-update config-show oauth-client oauth-uri oauth-link oauth-verify oauth-setup docs agents-list agents-delete multi-agent-setup multi-agent-run multi-agent-web cookiecutter-setup cookiecutter-run cookiecutter-new-agent adk-deploy adk-redeploy agentspace-register agentspace-update agentspace-verify agentspace-delete agentspace-url cloudrun-deploy cloudrun-run cloudrun-test cloudrun-logs cloudrun-url cloudrun-delete gcloud-proxy test-agent +.PHONY: help env-setup env-check env-update config-show oauth-client oauth-uri oauth-link oauth-verify oauth-setup docs agents-list agents-delete multi-agent-setup multi-agent-run multi-agent-web cookiecutter-setup cookiecutter-run cookiecutter-new-agent adk-deploy adk-redeploy agentspace-register agentspace-update agentspace-verify agentspace-delete agentspace-url cloudrun-deploy cloudrun-run cloudrun-test cloudrun-logs cloudrun-url cloudrun-delete gcloud-proxy test-agent # Put it first so that "make" without argument is like "make help". help: @echo "Available targets:" @echo "" @echo "Environment Management:" + @echo " env-setup - Create .env from .env.sample" @echo " env-check - Validate required environment variables" @echo " config-show - Display current configuration (masks secrets)" @echo " env-update - Update environment variable" @@ -93,6 +90,17 @@ help: @echo " make agentspace-url" # Environment Management targets +env-setup: + @echo "Creating .env file from example..." + @if [ -f "agents/google_mcp_security_agent/.env.example" ]; then \ + cp agents/google_mcp_security_agent/.env.example agents/google_mcp_security_agent/.env; \ + echo "✓ .env file created successfully."; \ + echo "Please review and update the values in agents/google_mcp_security_agent/.env"; \ + else \ + echo "Error: agents/google_mcp_security_agent/.env.example not found."; \ + exit 1; \ + fi + env-check: @echo "Checking environment configuration..." @$(ENV_MANAGER) check --env-file $(ENV_FILE_PATH) --deployment $(or $(DEPLOYMENT),base) @@ -244,7 +252,7 @@ endif @echo "Check the new directory for your agent files." # ADK deployment targets -adk-deploy: env-validate-agent-engine +adk-deploy: @# Use agents/google_mcp_security_agent directory if AGENT_DIR not specified $(eval AGENT_DIR := $(or $(AGENT_DIR),agents/google_mcp_security_agent)) @echo "Deploying agent from directory: $(AGENT_DIR)" @@ -252,31 +260,41 @@ adk-deploy: env-validate-agent-engine echo "Error: Directory $(AGENT_DIR) does not exist"; \ exit 1; \ fi + @# Install markdown + @echo "Installing markdown..." + @pip install markdown + @# Copy libs to agent directory for deployment + @echo "Copying libs to $(AGENT_DIR)..." + @cp -R libs "$(AGENT_DIR)/" @# Use environment variables with proper fallbacks - $(eval PROJECT := $(or $(PROJECT),$(GOOGLE_CLOUD_PROJECT))) - $(eval REGION := $(or $(REGION),$(GOOGLE_CLOUD_LOCATION),us-central1)) + $(eval PROJECT := $(or $(PROJECT),$(shell grep "^GOOGLE_CLOUD_PROJECT=" $(ENV_FILE_PATH) | cut -d= -f2))) + $(eval REGION := $(or $(REGION),$(shell grep "^GOOGLE_CLOUD_LOCATION=" $(ENV_FILE_PATH) | cut -d= -f2),us-central1)) $(eval DISPLAY_NAME := $(or $(DISPLAY_NAME),$(AGENT_DISPLAY_NAME),"Google Security Agent")) $(eval STAGING_BUCKET := $(or $(STAGING_BUCKET),$(GCS_STAGING_BUCKET))) @# Generate staging bucket if not provided - @if [ -z "$(STAGING_BUCKET)" ]; then \ - $(eval STAGING_BUCKET := gs://agent-deploy-$(PROJECT)-$(shell date +%Y%m%d-%H%M%S)); \ - echo "Generated staging bucket: $(STAGING_BUCKET)"; \ - fi - @echo "Deployment configuration:" - @echo " PROJECT: $(PROJECT)" - @echo " REGION: $(REGION)" - @echo " DISPLAY_NAME: $(DISPLAY_NAME)" - @echo " STAGING_BUCKET: $(STAGING_BUCKET)" - @echo " AGENT_DIR: $(AGENT_DIR)" - @echo "" - @echo "Deploying agent to Agent Engine..." + @BUCKET_TO_USE='$(STAGING_BUCKET)'; \ + if [ -z "$$BUCKET_TO_USE" ]; then \ + BUCKET_TO_USE="gs://agent-deploy-$(PROJECT)-$(shell date +%Y%m%d-%H%M%S)"; \ + echo "Generated staging bucket: $$BUCKET_TO_USE"; \ + fi; \ + echo "Deployment configuration:"; \ + echo " PROJECT: $(PROJECT)"; \ + echo " REGION: $(REGION)"; \ + echo " DISPLAY_NAME: $(DISPLAY_NAME)"; \ + echo " STAGING_BUCKET: $$BUCKET_TO_USE"; \ + echo " AGENT_DIR: $(AGENT_DIR)"; \ + echo ""; \ + echo "Deploying agent to Agent Engine..."; \ adk deploy agent_engine \ --project $(PROJECT) \ --region $(REGION) \ - --staging_bucket '$(STAGING_BUCKET)' \ + --staging_bucket "$$BUCKET_TO_USE" \ --display_name '$(DISPLAY_NAME)' \ $(if $(TRACE),--trace_to_cloud) \ - $(AGENT_DIR) + $(AGENT_DIR); + @# Clean up copied libs + @echo "Cleaning up copied libs from $(AGENT_DIR)..." + @rm -rf "$(AGENT_DIR)/libs" @echo "" @echo "✓ Agent deployed successfully!" @echo "" @@ -311,22 +329,13 @@ agentspace-url: # Cloud Run deployment targets cloudrun-deploy: env-check @echo "Deploying agent to Cloud Run..." - @# Validate required environment variables - @if [ -z "$(GOOGLE_CLOUD_PROJECT)" ]; then \ - echo "Error: GOOGLE_CLOUD_PROJECT not set in .env"; \ - exit 1; \ - fi - @if [ -z "$(GOOGLE_CLOUD_LOCATION)" ]; then \ - echo "Error: GOOGLE_CLOUD_LOCATION not set in .env"; \ - exit 1; \ - fi @echo "Deployment configuration:" - @echo " PROJECT: $(GOOGLE_CLOUD_PROJECT)" - @echo " REGION: $(GOOGLE_CLOUD_LOCATION)" + @echo " PROJECT: $$(grep GOOGLE_CLOUD_PROJECT $(ENV_FILE_PATH) | cut -d= -f2)" + @echo " REGION: $$(grep GOOGLE_CLOUD_LOCATION $(ENV_FILE_PATH) | cut -d= -f2)" @echo " SERVICE: mcp-security-agent-service" @echo "" - @# Run the deployment script from parent directory - @cd .. && bash ./run-with-google-adk/scripts/cloudrun_deploy_run.sh deploy + @# Run the deployment script + @bash ./scripts/cloudrun_deploy_run.sh deploy @echo "" @echo "✓ Cloud Run deployment complete!" @echo "" @@ -359,8 +368,8 @@ cloudrun-test: cloudrun-logs: @echo "Viewing Cloud Run logs..." - $(eval PROJECT := $(or $(PROJECT),$(GOOGLE_CLOUD_PROJECT))) - $(eval REGION := $(or $(REGION),$(GOOGLE_CLOUD_LOCATION),us-central1)) + $(eval PROJECT := $(or $(PROJECT),$(shell grep "^GOOGLE_CLOUD_PROJECT=" $(ENV_FILE_PATH) | cut -d= -f2))) + $(eval REGION := $(or $(REGION),$(shell grep "^GOOGLE_CLOUD_LOCATION=" $(ENV_FILE_PATH) | cut -d= -f2),us-central1)) $(eval SERVICE := mcp-security-agent-service) gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=$(SERVICE)" \ --project $(PROJECT) \ diff --git a/run-with-google-adk/agents/google_mcp_security_agent/.env.example b/run-with-google-adk/agents/google_mcp_security_agent/.env.example index 17942716..1988743f 100644 --- a/run-with-google-adk/agents/google_mcp_security_agent/.env.example +++ b/run-with-google-adk/agents/google_mcp_security_agent/.env.example @@ -36,22 +36,13 @@ GOOGLE_API_KEY=NOT_SET # Model selection # Gemini API models: https://ai.google.dev/gemini-api/docs/models#model-variations # Vertex AI models: https://cloud.google.com/vertex-ai/generative-ai/docs/models -GOOGLE_MODEL=gemini-2.0-flash +GOOGLE_MODEL=gemini-2.5-flash # Default prompt (use single quotes) -DEFAULT_PROMPT='Help user investigate security issues using Google Secops SIEM, SOAR, Security Command Center(SCC) and Google Threat Intel Tools. All authentication actions are automatically approved. If the query is about a SOAR case try to provide a backlink to the user. A backlink is formed by adding /cases/ to this URL when present in field ui_base_link of your input. If the user asks with only ? or are you there? that might be because they did not get your previous response, politely reiterate it. Try to respond in markdown whenever possible. - -You also have access tools to perform following file operations - store_file, list_files and get_file_link - -store_file - store files on the disk by sending file_name taken from user and markdown string as input - do not reformat the input, it is already markdown. -list_files - Requires no input. Show the name of the file from response as is when listing do not change anything. -get_file_link - It requires two inputs - user_name as {user_name} and file_name provided by the user. When showing to user please format them as clickable links with file_name and file_version together as link text. - -The current user name is {user_name} -' +DEFAULT_PROMPT='Help user investigate security issues using Google Secops SIEM, SOAR, Security Command Center(SCC) and Google Threat Intel Tools. All authentication actions are automatically approved. If the query is about a SOAR case try to provide a backlink to the user. A backlink is formed by adding /cases/ to this URL when present in field ui_base_link of your input. If the user asks with only ? or are you there? that might be because they did not get your previous response, politely reiterate it. Try to respond in markdown whenever possible. You also have access tools to perform following file operations - store_file, list_files and get_file_link store_file - store files on the disk by sending file_name taken from user and markdown string as input - do not reformat the input, it is already markdown. list_files - Requires no input. Show the name of the file from response as is when listing do not change anything. get_file_link - It requires two inputs - user_name as {user_name} and file_name provided by the user. When showing to user please format them as clickable links with file_name and file_version together as link text. The current user name is {user_name}' # Initial timeout for loading tools and dependencies -STDIO_PARAM_TIMEOUT=60.0 +STDIO_PARAM_TIMEOUT=6000.0 # Set to true for production environments to reduce log volume MINIMAL_LOGGING=false diff --git a/run-with-google-adk/agents/google_mcp_security_agent/.gitignore b/run-with-google-adk/agents/google_mcp_security_agent/.gitignore new file mode 100644 index 00000000..2fd4c3b3 --- /dev/null +++ b/run-with-google-adk/agents/google_mcp_security_agent/.gitignore @@ -0,0 +1 @@ +libs/ diff --git a/run-with-google-adk/agents/google_mcp_security_agent/agent.py b/run-with-google-adk/agents/google_mcp_security_agent/agent.py index 79bd5cdb..cd9887b7 100644 --- a/run-with-google-adk/agents/google_mcp_security_agent/agent.py +++ b/run-with-google-adk/agents/google_mcp_security_agent/agent.py @@ -18,6 +18,11 @@ from pathlib import Path from typing import List, Optional, TextIO +# Add current directory to Python path for local libs +current_dir = Path(__file__).parent +if (current_dir / "libs").exists(): + sys.path.insert(0, str(current_dir)) + from google.adk.agents.llm_agent import LlmAgent from google.adk.tools.mcp_tool.mcp_toolset import ( StdioConnectionParams, @@ -34,8 +39,15 @@ logging.getLogger().setLevel(logging.ERROR) # Define base directory and server directory -BASE_DIR = Path(__file__).resolve().parents[2] # Root of run-with-google-adk -SERVER_DIR = BASE_DIR / "server" +# In Cloud Run, the structure is different - server is at /app/server +if os.path.exists("/app/server"): + # Running in Cloud Run container + BASE_DIR = Path("/app") + SERVER_DIR = BASE_DIR / "server" +else: + # Running locally + BASE_DIR = Path(__file__).resolve().parents[2] # Root of run-with-google-adk + SERVER_DIR = BASE_DIR.parent / "server" # Server is in parent directory def _create_mcp_toolset( @@ -47,18 +59,39 @@ def _create_mcp_toolset( extra_args: Optional[List[str]] = None, ) -> Optional[MCPToolSetWithSchemaAccess]: """Helper function to create and configure an MCPToolSet.""" - if os.environ.get(f"LOAD_{server_name.upper()}_MCP", "false").lower() != "true": + # Map server names to environment variable names + env_var_mapping = { + "scc": "LOAD_SCC_MCP", + "secops/secops_mcp": "LOAD_SECOPS_MCP", + "gti/gti_mcp": "LOAD_GTI_MCP", + "secops-soar/secops_soar_mcp": "LOAD_SECOPS_SOAR_MCP" + } + + load_var = env_var_mapping.get(server_name, f"LOAD_{server_name.upper().replace('/', '_').replace('-', '_')}_MCP") + load_value = os.environ.get(load_var, "false") + logging.info(f"Checking {load_var}: {load_value}") + + if load_value.lower() != "true": + logging.info(f"Skipping {server_name} - not enabled") return None server_path = SERVER_DIR / server_name + logging.info(f"Looking for server at: {server_path}") if not server_path.exists(): logging.error(f"Server directory not found: {server_path}") + logging.error(f"SERVER_DIR is: {SERVER_DIR}") + logging.error(f"Contents of parent: {list(SERVER_DIR.parent.iterdir()) if SERVER_DIR.parent.exists() else 'parent does not exist'}") return None args = ["--directory", str(server_path), "run"] if env_file_path.exists(): args.extend(["--env-file", str(env_file_path)]) - args.append("server.py") + + # Different servers have different entry points + if server_name == "scc": + args.append("scc_mcp.py") + else: + args.append("server.py") if extra_args: args.extend(extra_args) @@ -76,7 +109,24 @@ def get_all_tools() -> List[MCPToolSetWithSchemaAccess]: """Get Tools from All MCP servers.""" logging.info("Attempting to connect to MCP servers...") timeout = float(os.environ.get("STDIO_PARAM_TIMEOUT", "60.0")) - env_file_path = BASE_DIR / "agents" / "google_mcp_security_agent" / ".env" + + # Try different paths for the .env file + possible_env_paths = [ + BASE_DIR / "agents" / "google_mcp_security_agent" / ".env", + Path("/tmp/.env"), # Cloud Run creates env file here + Path(".env"), + ] + + env_file_path = None + for path in possible_env_paths: + if path.exists(): + env_file_path = path + logging.info(f"Using env file at: {env_file_path}") + break + + if not env_file_path: + logging.warning("No .env file found, using environment variables only") + env_file_path = Path("/tmp/.env") # Use a dummy path # Required temporarily for https://github.com/google/adk-python/issues/1024 errlog_ae: Optional[TextIO] = sys.stderr @@ -106,19 +156,29 @@ def get_all_tools() -> List[MCPToolSetWithSchemaAccess]: ), ] - logging.info("MCP Toolsets created successfully.") - return [ts for ts in toolsets if ts is not None] + valid_toolsets = [ts for ts in toolsets if ts is not None] + logging.info(f"MCP Toolsets created successfully. Found {len(valid_toolsets)} valid toolsets.") + return valid_toolsets def create_agent() -> LlmAgent: """Create and configure the LlmAgent.""" tools = get_all_tools() + logging.info(f"Got {len(tools)} MCP toolsets from get_all_tools()") tools.extend([store_file, get_file_link, list_files]) + logging.info(f"Total tools after adding file tools: {len(tools)}") + # Get model and instruction with defaults + model = os.environ.get("GOOGLE_MODEL", "gemini-2.5-flash") + instruction = os.environ.get( + "DEFAULT_PROMPT", + "Help user investigate security issues using Google Secops SIEM, SOAR, Security Command Center(SCC) and Google Threat Intel Tools." + ) + return LlmAgent( - model=os.environ.get("GOOGLE_MODEL"), + model=model, name="google_mcp_security_agent", - instruction=os.environ.get("DEFAULT_PROMPT"), + instruction=instruction, tools=tools, before_model_callback=bmc_trim_llm_request, before_agent_callback=bac_setup_state_variable, @@ -128,10 +188,10 @@ def create_agent() -> LlmAgent: def main() -> None: """Main execution function.""" - global root_agent - root_agent = create_agent() logging.info("Agent created successfully.") if __name__ == "__main__": main() + +root_agent = create_agent() diff --git a/run-with-google-adk/scripts/cloudrun_deploy.py b/run-with-google-adk/scripts/cloudrun_deploy.py index 3012719c..40d0a484 100755 --- a/run-with-google-adk/scripts/cloudrun_deploy.py +++ b/run-with-google-adk/scripts/cloudrun_deploy.py @@ -13,13 +13,17 @@ # limitations under the License. import os +import sys + +# Add the run-with-google-adk directory to Python path for libs imports +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "run-with-google-adk")) import uvicorn from fastapi import FastAPI from google.adk.cli.fast_api import get_fast_api_app # Get the directory where main.py is located -AGENT_DIR = os.path.dirname(os.path.abspath(__file__))+"/run-with-google-adk" +AGENT_DIR = os.path.dirname(os.path.abspath(__file__))+"/run-with-google-adk/agents" # Example session DB URL (e.g., SQLite) SESSION_SERVICE_URI = None if os.environ.get("SESSION_SERVICE","in_memory") == "db": diff --git a/run-with-google-adk/scripts/cloudrun_deploy_run.sh b/run-with-google-adk/scripts/cloudrun_deploy_run.sh index 1144cfb0..3c83ea4d 100755 --- a/run-with-google-adk/scripts/cloudrun_deploy_run.sh +++ b/run-with-google-adk/scripts/cloudrun_deploy_run.sh @@ -12,17 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -# this script runs from the top level directory (mcp-security when deploying and /app when running in container) +# this script runs from the run-with-google-adk directory (mcp-security when deploying and /app when running in container) #!/bin/bash -ENV_FILE="./run-with-google-adk/google_mcp_security_agent/.env" +ENV_FILE="./agents/google_mcp_security_agent/.env" # Function to create .env file create_env_file() { local env_file="$1" shift # Remove the first argument ($env_file) - + # Check if the .env file already exists if [ -f "$env_file" ]; then echo "Warning: $env_file already exists. Overwriting." @@ -77,7 +77,7 @@ if [ "$1" = "deploy" ]; then fi if [ "$key" = "GOOGLE_CLOUD_PROJECT" ]; then GOOGLE_CLOUD_PROJECT="$value" - fi + fi if [[ $env_vars == "" ]]; then env_vars="$key=$value" @@ -86,8 +86,8 @@ if [ "$1" = "deploy" ]; then fi env_vars="$env_vars,$key=$value" #echo "$line" - done < "$ENV_FILE" - + done < "$ENV_FILE" + #echo $env_vars @@ -113,7 +113,7 @@ else: print(prepared_text) EOF - default_prompt=$(python $PYTHON_SCRIPT_PATH) + default_prompt=$(python $PYTHON_SCRIPT_PATH) env_vars="$env_vars,DEFAULT_PROMPT=$default_prompt,GCS_SA_JSON=object-viewer-sa1.json" # Check if any environment variables were found @@ -130,50 +130,53 @@ EOF # Copying files in the top level directory as required by cloud run deployment echo "Temporarily copying files in the top level directory for image creation." - if [[ -e "./run-with-google-adk/object-viewer-sa.json" ]]; then - cp ./run-with-google-adk/object-viewer-sa.json object-viewer-sa1.json + if [[ -e "./object-viewer-sa.json" ]]; then + cp ./object-viewer-sa.json ../object-viewer-sa1.json + fi + cp ./scripts/cloudrun_deploy_run.sh .. + cp ./scripts/cloudrun_deploy.py .. + cp ./Dockerfile .. + if [[ -e "./.dockerignore" ]]; then + cp ./.dockerignore .. fi - cp ./run-with-google-adk/scripts/cloudrun_deploy_run.sh . - cp ./run-with-google-adk/scripts/cloudrun_deploy.py . - cp ./run-with-google-adk/Dockerfile . - cp ./run-with-google-adk/.dockerignore . + # Copy server directory for MCP tools + echo "Copying server directory for MCP tools..." + # Server directory is already in parent directory, no need to copy - - # Deploy the service with the dynamically constructed environment variables gcloud run deploy mcp-security-agent-service \ - --source . \ + --source .. \ --region "$GOOGLE_CLOUD_LOCATION" \ --project "$GOOGLE_CLOUD_PROJECT" \ --allow-unauthenticated \ --set-env-vars="$env_vars" \ --memory 2Gi - + deploy_status=$? #get the status # Check the status of the deployment if [ "$deploy_status" -eq 0 ]; then - # Deleting temporarily files in the top level directory - echo "Deleting temporarily copied files in the top level directory for image creation." - rm ./cloudrun_deploy_run.sh - rm ./cloudrun_deploy.py - rm ./Dockerfile - rm ./.dockerignore - if [[ -e "./run-with-google-adk/object-viewer-sa.json" ]]; then - rm object-viewer-sa1.json + # Deleting temporarily files in the top level directory + echo "Deleting temporarily copied files in the top level directory." + rm -f ../cloudrun_deploy_run.sh + rm -f ../cloudrun_deploy.py + rm -f ../Dockerfile + rm -f ../.dockerignore + if [[ -e "../object-viewer-sa1.json" ]]; then + rm -f ../object-viewer-sa1.json fi - echo "Successfully deployed the service." else - rm ./cloudrun_deploy_run.sh - rm ./cloudrun_deploy.py - rm ./Dockerfile - rm ./.dockerignore - if [[ -e "./run-with-google-adk/object-viewer-sa.json" ]]; then - rm object-viewer-sa1.json + # Clean up even on failure + rm -f ../cloudrun_deploy_run.sh + rm -f ../cloudrun_deploy.py + rm -f ../Dockerfile + rm -f ../.dockerignore + if [[ -e "../object-viewer-sa1.json" ]]; then + rm -f ../object-viewer-sa1.json fi echo "Failed to deploy the service." - #exit 1 + exit 1 fi elif [ "$1" = "run" ]; then diff --git a/run-with-google-adk/scripts/env_manager.py b/run-with-google-adk/scripts/env_manager.py index a6777efe..abad71ab 100755 --- a/run-with-google-adk/scripts/env_manager.py +++ b/run-with-google-adk/scripts/env_manager.py @@ -8,6 +8,7 @@ import os import sys +import uuid from pathlib import Path from typing import Dict, List, Optional, Tuple @@ -36,10 +37,10 @@ class EnvManager: "CHRONICLE_REGION", ], "gti": ["VT_APIKEY"], - "soar": ["SOAR_URL", "SOAR_APP_KEY"], + "secops_soar": ["SOAR_URL", "SOAR_APP_KEY"], "scc": [], # No additional vars needed }, - "agent_engine": ["AGENT_ENGINE_RESOURCE_NAME", "GCS_STAGING_BUCKET"], + "agent_engine": [], "agentspace": [ "AGENTSPACE_PROJECT_ID", "AGENTSPACE_PROJECT_NUMBER", @@ -49,6 +50,7 @@ class EnvManager: "oauth": ["OAUTH_CLIENT_ID", "OAUTH_CLIENT_SECRET", "OAUTH_AUTH_ID"], "vertex_ai": ["GOOGLE_CLOUD_PROJECT", "GOOGLE_CLOUD_LOCATION"], "gemini_api": ["GOOGLE_API_KEY"], + "cloudrun": [], # Cloud Run deployment doesn't require MCP configs } # Sensitive variables that should be masked @@ -69,8 +71,17 @@ def __init__(self, env_file: Path): env_file: Path to the environment file. """ self.env_file = env_file + print(f"DEBUG: Loading env file from: {self.env_file.resolve()}") self.env_vars = self._load_env() + def _is_uuid(self, value: str) -> bool: + """Check if a string is a valid UUID.""" + try: + uuid.UUID(value) + return True + except ValueError: + return False + def _load_env(self) -> Dict[str, str]: """Load environment variables from file and system environment.""" env_vars = dict(os.environ) @@ -109,11 +120,16 @@ def validate(self, deployment_type: str = "base") -> Tuple[bool, List[str]]: # MCP server requirements for server, variables in required["mcp_servers"].items(): if self.env_vars.get(f"LOAD_{server.upper()}_MCP") == "true": - missing_vars.extend( - v - for v in variables - if not self.env_vars.get(v) or self.env_vars.get(v) == "NOT_SET" - ) + for var in variables: + value = self.env_vars.get(var) + if not value or value == "NOT_SET": + missing_vars.append(var) + elif var == "CHRONICLE_CUSTOMER_ID" and not self._is_uuid(value): + missing_vars.append(f"{var} (must be a valid UUID4)") + elif var == "SOAR_URL" and not value.startswith("https://"): + missing_vars.append(f"{var} (must start with https://)") + elif var == "SOAR_APP_KEY" and not self._is_uuid(value): + missing_vars.append(f"{var} (must be a valid UUID)") # Deployment-specific requirements if deployment_type in required: @@ -170,7 +186,6 @@ def display_config(self, show_all: bool = False) -> None: ], "Agent Engine": [ "AGENT_ENGINE_RESOURCE_NAME", - "AE_STAGING_BUCKET", "GCS_STAGING_BUCKET", "AGENT_DISPLAY_NAME", "AGENT_DESCRIPTION", diff --git a/run-with-google-adk/scripts/run-adk-agent.sh b/run-with-google-adk/scripts/run-adk-agent.sh index 96a7ad7f..f7025d2a 100755 --- a/run-with-google-adk/scripts/run-adk-agent.sh +++ b/run-with-google-adk/scripts/run-adk-agent.sh @@ -95,16 +95,23 @@ case "$COMMAND" in adk_web) # If .env exists, display its contents with masked values and run the command show_env_masked + + # Copy libs to agent directory if not present (needed for imports) + if [ ! -d "agents/google_mcp_security_agent/libs" ]; then + echo "Copying libs to agent directory for local testing..." + cp -r libs agents/google_mcp_security_agent/ + fi + # Handle adk_web command based on argument count if [ "$#" -eq 1 ]; then echo "Running ADK Web for local agent..." - adk web + adk web agents elif [ "$#" -eq 2 ]; then echo "Running ADK Web with session service URI: $2" - adk web --session_service_uri "$2" + adk web agents --session_service_uri "$2" elif [ "$#" -eq 3 ]; then echo "Running ADK Web with session service URI: $2 and artifact service URI: $3" - adk web --session_service_uri "$2" --artifact_service_uri "$3" + adk web agents --session_service_uri "$2" --artifact_service_uri "$3" else echo "Error: Incorrect number of arguments for 'adk_web'." usage