Skip to main content
Glama
configure_environment.py15 kB
#!/usr/bin/env python3 """ Configure Testing Environment for MCP Integration Tests Sets up the testing environment including directories, permissions, and validation of prerequisites. """ import os import sys import json import asyncio import tempfile import subprocess from pathlib import Path from typing import Dict, Any, List import logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class TestEnvironmentConfigurator: """Configures the testing environment for MCP integration tests.""" def __init__(self, base_dir: Path = None): self.base_dir = base_dir or Path(tempfile.gettempdir()) / "shannon-mcp-integration-test" self.test_projects_dir = self.base_dir / "test-projects" self.test_hooks_dir = self.base_dir / "test-hooks" self.test_sessions_dir = self.base_dir / "test-sessions" self.test_results_dir = self.base_dir / "test-results" async def configure(self) -> Dict[str, Any]: """ Configure the complete testing environment. Returns: Configuration details and validation results """ logger.info("Configuring MCP integration testing environment") # Create directory structure self._create_test_directories() # Set up test projects projects = await self._setup_test_projects() # Configure test hooks hooks = await self._configure_test_hooks() # Prepare session environment session_env = await self._prepare_session_environment() # Validate prerequisites validation = await self._validate_prerequisites() # Create environment file env_file = await self._create_environment_file() return { "base_dir": str(self.base_dir), "directories": { "projects": str(self.test_projects_dir), "hooks": str(self.test_hooks_dir), "sessions": str(self.test_sessions_dir), "results": str(self.test_results_dir) }, "test_projects": projects, "test_hooks": hooks, "session_environment": session_env, "validation": validation, "environment_file": env_file, "status": "ready" if validation["all_prerequisites_met"] else "incomplete" } def _create_test_directories(self): """Create all necessary test directories.""" directories = [ self.base_dir, self.test_projects_dir, self.test_hooks_dir, self.test_sessions_dir, self.test_results_dir, self.test_results_dir / "agent-reports", self.test_results_dir / "validation-logs", self.test_results_dir / "gate-decisions" ] for directory in directories: directory.mkdir(parents=True, exist_ok=True) logger.info(f"Created directory: {directory}") async def _setup_test_projects(self) -> List[Dict[str, Any]]: """Set up test project directories with various configurations.""" logger.info("Setting up test projects...") test_projects = [] # Project 1: Simple Python project python_project = self.test_projects_dir / "python-test-project" python_project.mkdir(exist_ok=True) # Create project files (python_project / "main.py").write_text("""#!/usr/bin/env python3 # Test Python project for MCP validation print("Hello from Python test project") def test_function(): return "MCP Integration Test" """) (python_project / "requirements.txt").write_text("""pytest>=7.0.0 asyncio """) (python_project / ".shannon-mcp").mkdir(exist_ok=True) (python_project / ".shannon-mcp" / "project.yaml").write_text("""name: python-test-project type: python version: 1.0.0 description: Test Python project for MCP integration """) test_projects.append({ "name": "python-test-project", "path": str(python_project), "type": "python", "files": ["main.py", "requirements.txt", ".shannon-mcp/project.yaml"] }) # Project 2: Node.js project node_project = self.test_projects_dir / "node-test-project" node_project.mkdir(exist_ok=True) (node_project / "index.js").write_text("""// Test Node.js project for MCP validation console.log("Hello from Node.js test project"); function testFunction() { return "MCP Integration Test"; } module.exports = { testFunction }; """) (node_project / "package.json").write_text(json.dumps({ "name": "node-test-project", "version": "1.0.0", "description": "Test Node.js project for MCP integration", "main": "index.js" }, indent=2)) test_projects.append({ "name": "node-test-project", "path": str(node_project), "type": "node", "files": ["index.js", "package.json"] }) # Project 3: Empty project (for discovery testing) empty_project = self.test_projects_dir / "empty-test-project" empty_project.mkdir(exist_ok=True) (empty_project / ".gitkeep").touch() test_projects.append({ "name": "empty-test-project", "path": str(empty_project), "type": "empty", "files": [".gitkeep"] }) return test_projects async def _configure_test_hooks(self) -> List[Dict[str, Any]]: """Configure test hooks for validation.""" logger.info("Configuring test hooks...") test_hooks = [] # Hook 1: File creation hook file_hook = self.test_hooks_dir / "file-creation-hook.sh" file_hook.write_text("""#!/bin/bash # Test hook that creates a file to validate execution MARKER_FILE="/tmp/mcp-hook-executed-$(date +%s).marker" echo "Hook executed at $(date)" > "$MARKER_FILE" echo "Session ID: $SESSION_ID" >> "$MARKER_FILE" echo "Event: $EVENT_TYPE" >> "$MARKER_FILE" echo "$MARKER_FILE" """) file_hook.chmod(0o755) test_hooks.append({ "name": "file-creation-hook", "path": str(file_hook), "type": "bash", "purpose": "Creates marker file to validate execution" }) # Hook 2: Python hook for complex validation python_hook = self.test_hooks_dir / "validation-hook.py" python_hook.write_text("""#!/usr/bin/env python3 import os import sys import json from datetime import datetime # Test hook that performs validation validation_result = { "timestamp": datetime.now().isoformat(), "session_id": os.environ.get("SESSION_ID", "unknown"), "event_type": os.environ.get("EVENT_TYPE", "unknown"), "environment": dict(os.environ), "validation": "success" } # Write validation result output_file = f"/tmp/mcp-validation-{os.getpid()}.json" with open(output_file, 'w') as f: json.dump(validation_result, f, indent=2) print(f"Validation complete: {output_file}") """) python_hook.chmod(0o755) test_hooks.append({ "name": "validation-hook", "path": str(python_hook), "type": "python", "purpose": "Performs complex validation with JSON output" }) # Hook 3: Global hook for user scope testing global_hook = self.test_hooks_dir / "global-scope-hook.sh" global_hook.write_text("""#!/bin/bash # Test hook for global/user scope validation USER_MARKER="$HOME/.shannon-mcp-global-hook-marker" echo "Global hook executed at $(date)" >> "$USER_MARKER" echo "Modified user scope successfully" """) global_hook.chmod(0o755) test_hooks.append({ "name": "global-scope-hook", "path": str(global_hook), "type": "bash", "purpose": "Tests global/user scope modifications" }) return test_hooks async def _prepare_session_environment(self) -> Dict[str, Any]: """Prepare the session testing environment.""" logger.info("Preparing session environment...") # Create session templates session_templates = self.test_sessions_dir / "templates" session_templates.mkdir(exist_ok=True) # Basic session config basic_session = { "name": "test-session-basic", "model": "claude-3-opus-20240229", "temperature": 0.7, "max_tokens": 1000, "system_prompt": "You are a test assistant for MCP integration validation." } (session_templates / "basic-session.json").write_text( json.dumps(basic_session, indent=2) ) # Streaming session config streaming_session = { "name": "test-session-streaming", "model": "claude-3-opus-20240229", "streaming": True, "timeout": 30, "buffer_size": 1048576 } (session_templates / "streaming-session.json").write_text( json.dumps(streaming_session, indent=2) ) # Create test prompts prompts_dir = self.test_sessions_dir / "prompts" prompts_dir.mkdir(exist_ok=True) test_prompts = { "simple": "Echo 'MCP Integration Test Success'", "file_operation": "Create a file named 'test-output.txt' with content 'MCP Test'", "streaming": "Count from 1 to 10 slowly, showing each number", "error": "This should trigger an error for testing" } for name, prompt in test_prompts.items(): (prompts_dir / f"{name}.txt").write_text(prompt) return { "templates_dir": str(session_templates), "prompts_dir": str(prompts_dir), "session_configs": ["basic-session.json", "streaming-session.json"], "test_prompts": list(test_prompts.keys()) } async def _validate_prerequisites(self) -> Dict[str, Any]: """Validate all prerequisites for testing.""" logger.info("Validating prerequisites...") validation_results = { "python_version": sys.version, "python_valid": sys.version_info >= (3, 11), "claude_code_available": False, "disk_space_available": False, "permissions_valid": False, "network_accessible": False } # Check for Claude Code try: result = subprocess.run( ["which", "claude-code"], capture_output=True, text=True ) validation_results["claude_code_available"] = result.returncode == 0 if result.returncode == 0: validation_results["claude_code_path"] = result.stdout.strip() except: pass # Check disk space (need at least 1GB) try: stat = os.statvfs(self.base_dir) free_space_gb = (stat.f_bavail * stat.f_frsize) / (1024**3) validation_results["disk_space_gb"] = free_space_gb validation_results["disk_space_available"] = free_space_gb >= 1.0 except: pass # Check permissions try: test_file = self.base_dir / ".permission-test" test_file.touch() test_file.chmod(0o755) validation_results["permissions_valid"] = test_file.stat().st_mode & 0o755 == 0o755 test_file.unlink() except: pass # Check network (can we reach localhost?) try: import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) result = sock.connect_ex(('127.0.0.1', 8765)) sock.close() validation_results["network_accessible"] = True validation_results["mcp_port_available"] = result != 0 except: pass # Overall validation validation_results["all_prerequisites_met"] = all([ validation_results["python_valid"], validation_results["disk_space_available"], validation_results["permissions_valid"], validation_results["network_accessible"] ]) return validation_results async def _create_environment_file(self) -> str: """Create environment configuration file.""" env_config = { "SHANNON_MCP_TEST_BASE": str(self.base_dir), "SHANNON_MCP_TEST_PROJECTS": str(self.test_projects_dir), "SHANNON_MCP_TEST_HOOKS": str(self.test_hooks_dir), "SHANNON_MCP_TEST_SESSIONS": str(self.test_sessions_dir), "SHANNON_MCP_TEST_RESULTS": str(self.test_results_dir), "SHANNON_MCP_TEST_MODE": "integration", "SHANNON_MCP_ALLOW_DESTRUCTIVE": "true" } env_file = self.base_dir / "test.env" with open(env_file, 'w') as f: for key, value in env_config.items(): f.write(f'export {key}="{value}"\n') logger.info(f"Created environment file: {env_file}") return str(env_file) async def cleanup(self): """Clean up test environment.""" logger.info(f"Cleaning up test environment at {self.base_dir}") if self.base_dir.exists() and "test" in str(self.base_dir): import shutil shutil.rmtree(self.base_dir) logger.info("Cleanup complete") async def main(): """Main configuration entry point.""" configurator = TestEnvironmentConfigurator() # Configure environment result = await configurator.configure() # Pretty print results print("\n" + "="*60) print("MCP Integration Test Environment Configuration") print("="*60) print(json.dumps(result, indent=2)) if result["status"] == "ready": print("\n✅ Environment ready for testing!") print(f"\nTo use this environment:") print(f" source {result['environment_file']}") print(f"\nTest projects: {result['directories']['projects']}") print(f"Test hooks: {result['directories']['hooks']}") else: print("\n❌ Environment configuration incomplete!") print("\nMissing prerequisites:") for key, value in result["validation"].items(): if key.endswith("_valid") or key.endswith("_available"): if not value: print(f" - {key}: {value}") if __name__ == "__main__": asyncio.run(main())

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/krzemienski/shannon-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server