Skip to main content
Glama
config.pyโ€ข9.24 kB
"""Configuration models for delegation MCP server.""" from typing import Any, Literal from pathlib import Path from pydantic import BaseModel, Field import yaml import re from collections import defaultdict class ConfigValidationError(Exception): """Exception raised when configuration validation fails.""" def __init__(self, errors: list[str]): self.errors = errors super().__init__(f"Configuration validation failed: {'; '.join(errors)}") class AgentCapabilities(BaseModel): """Capability scores for an agent.""" security_audit: float = 0.5 vulnerability_scan: float = 0.5 code_review: float = 0.5 architecture: float = 0.5 refactoring: float = 0.5 quick_fix: float = 0.5 documentation: float = 0.5 testing: float = 0.5 performance: float = 0.5 git_workflow: float = 0.5 # Git operations (commit, push, merge, rebase) github_operations: float = 0.5 # GitHub operations (PR, issues, releases) general: float = 0.5 # Fallback capability class OrchestratorConfig(BaseModel): """Configuration for a single orchestrator/CLI.""" name: str command: str | list[str] args: list[str] = Field(default_factory=list) enabled: bool = True env: dict[str, str] = Field(default_factory=dict) timeout: int = 300 # seconds max_retries: int = 3 capabilities: AgentCapabilities = Field(default_factory=AgentCapabilities) cost_per_1k_tokens: float = 0.001 # Cost estimate for routing decisions class DelegationRule(BaseModel): """Rule for delegating tasks to specific orchestrators.""" pattern: str # Regex pattern to match delegate_to: str # Target orchestrator name priority: int = 0 # Higher priority wins requires_approval: bool = False description: str = "" class DelegationConfig(BaseModel): """Main configuration for delegation MCP server.""" orchestrator: Literal["claude"] = "claude" # Primary orchestrator orchestrators: dict[str, OrchestratorConfig] = Field(default_factory=dict) rules: list[DelegationRule] = Field(default_factory=list) auto_approve: bool = False log_delegations: bool = True routing_strategy: Literal["capability", "pattern", "hybrid"] = "capability" # Routing approach def to_yaml(self, path: Path) -> None: """Save configuration to YAML file.""" with open(path, "w", encoding="utf-8") as f: yaml.dump(self.model_dump(), f, default_flow_style=False) def get_orchestrator(self, name: str) -> OrchestratorConfig | None: """Get orchestrator configuration by name.""" return self.orchestrators.get(name) def find_delegation_rule(self, query: str) -> DelegationRule | None: """Find matching delegation rule for query.""" matching_rules = [ rule for rule in self.rules if re.search(rule.pattern, query, re.IGNORECASE) ] if not matching_rules: return None # Return highest priority rule return max(matching_rules, key=lambda r: r.priority) def _validate_minimum_agents(self) -> list[str]: """Validate that at least 2 agents are enabled.""" errors = [] enabled_count = sum( 1 for orch in self.orchestrators.values() if orch.enabled ) if enabled_count < 2: errors.append( f"At least 2 agents must be enabled, but only {enabled_count} " f"{'is' if enabled_count == 1 else 'are'} enabled. " f"Enable more agents in orchestrators configuration." ) return errors def _validate_regex_patterns(self) -> list[str]: """Validate YAML regex syntax in routing rules.""" errors = [] for i, rule in enumerate(self.rules): try: # Attempt to compile the regex pattern re.compile(rule.pattern) except re.error as e: errors.append( f"Rule #{i + 1} (delegate_to: {rule.delegate_to}): " f"Invalid regex pattern '{rule.pattern}': {str(e)}" ) return errors def _validate_agent_references(self) -> list[str]: """Validate that all referenced agents exist.""" errors = [] # Check primary orchestrator exists if self.orchestrator not in self.orchestrators: errors.append( f"Primary orchestrator '{self.orchestrator}' is not defined " f"in orchestrators configuration. Available orchestrators: " f"{', '.join(self.orchestrators.keys())}" ) # Check all delegation rule targets exist for i, rule in enumerate(self.rules): if rule.delegate_to not in self.orchestrators: errors.append( f"Rule #{i + 1} (pattern: '{rule.pattern}'): " f"Target orchestrator '{rule.delegate_to}' is not defined. " f"Available orchestrators: {', '.join(self.orchestrators.keys())}" ) return errors def _validate_no_circular_delegation(self) -> list[str]: """ Validate that there are no obvious circular delegation patterns. Note: In the current delegation system, queries are processed once and returned to the user - there is no automatic re-delegation. Therefore, true circular delegation is not possible. This check looks for potential issues like: - Duplicate patterns delegating to different orchestrators (ambiguous routing) - Rules with very similar patterns that might cause confusion Since circular delegation is not a real concern in this architecture, this validation performs only basic sanity checks. """ errors = [] if not self.rules: return errors # Check for duplicate or highly similar patterns # This could cause ambiguous delegation behavior pattern_targets: dict[str, list[str]] = defaultdict(list) for rule in self.rules: # Normalize pattern for comparison (case-insensitive) normalized_pattern = rule.pattern.lower().strip() pattern_targets[normalized_pattern].append(rule.delegate_to) # Check for exact duplicate patterns with different targets for pattern, targets in pattern_targets.items(): unique_targets = set(targets) if len(unique_targets) > 1: # Same pattern delegates to multiple different orchestrators # This is actually fine - highest priority wins # But if priorities are the same, it could be ambiguous # Find rules with this pattern matching_rules = [ r for r in self.rules if r.pattern.lower().strip() == pattern ] # Check if they have the same priority priorities = {r.priority for r in matching_rules} if len(priorities) == 1: # All have same priority - ambiguous! targets_str = ", ".join(sorted(unique_targets)) errors.append( f"Ambiguous delegation: pattern '{pattern}' delegates to " f"multiple orchestrators ({targets_str}) with the same priority. " f"This could cause unpredictable behavior. Consider using " f"different priorities or combining into a single rule." ) return errors def validate(self) -> None: """ Validate the entire configuration. Performs the following validations: 1. At least 2 agents are enabled 2. All regex patterns in routing rules are valid 3. All referenced agents exist in orchestrators 4. No circular delegation rules exist Raises: ConfigValidationError: If any validation fails, with detailed error messages. """ all_errors: list[str] = [] # Run all validation checks all_errors.extend(self._validate_minimum_agents()) all_errors.extend(self._validate_regex_patterns()) all_errors.extend(self._validate_agent_references()) all_errors.extend(self._validate_no_circular_delegation()) # Raise exception if any errors found if all_errors: raise ConfigValidationError(all_errors) @classmethod def from_yaml(cls, path: Path, validate: bool = True) -> "DelegationConfig": """ Load configuration from YAML file. Args: path: Path to YAML configuration file validate: Whether to validate the configuration after loading (default: True) Returns: DelegationConfig instance Raises: ConfigValidationError: If validation is enabled and fails """ with open(path, encoding="utf-8") as f: data = yaml.safe_load(f) config = cls(**data) if validate: config.validate() return config

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/carlosduplar/multi-agent-mcp'

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