Skip to main content
Glama

MCP Git Server

by MementoRC
github_config.py14.7 kB
"""GitHub integration configuration model with validation. This module provides GitHub-specific configuration for the MCP Git Server, including API settings, authentication, webhook handling, and rate limiting. Key features: - GitHub API configuration and timeouts - Authentication token management - Webhook security and validation - Rate limiting and retry policies - GitHub Enterprise support - PR and issue integration settings Configuration areas: - API settings: Base URL, timeouts, retries - Authentication: Token validation, scopes - Webhooks: Secret validation, event filtering - Rate limiting: Buffer management, backoff - Integration: PR policies, issue linking Example usage: >>> from mcp_server_git.configuration import GitHubConfig >>> >>> config = GitHubConfig( ... api_token="ghp_xxxxxxxxxxxx", ... webhook_secret="my-webhook-secret" ... ) >>> print(f"API URL: {config.api_base_url}") API URL: https://api.github.com >>> # GitHub Enterprise configuration >>> enterprise_config = GitHubConfig( ... api_base_url="https://github.enterprise.com/api/v3", ... api_token="ghp_enterprise_token" ... ) See also: - server_config: Main server configuration - git_config: Git-specific configuration """ import re from pydantic import BaseModel, Field, HttpUrl, field_validator class GitHubConfig(BaseModel): """GitHub integration configuration with comprehensive validation. This class provides configuration for GitHub API integration, webhook handling, and GitHub-specific policies within the MCP Git Server. Attributes: API Settings: api_base_url: GitHub API base URL (GitHub.com or Enterprise) api_version: GitHub API version to use api_timeout_seconds: Timeout for API requests max_retries: Maximum retry attempts for failed requests retry_backoff_factor: Exponential backoff multiplier Authentication: api_token: GitHub API token (validated format) token_scopes: Required token scopes validate_token_on_startup: Validate token at startup Rate Limiting: rate_limit_buffer: Requests to keep in reserve rate_limit_threshold: Percentage threshold for warnings auto_retry_rate_limited: Auto retry when rate limited max_rate_limit_wait: Maximum wait time for rate limits Webhook Configuration: webhook_secret: Secret for webhook validation allowed_webhook_events: List of allowed webhook events webhook_timeout: Timeout for webhook processing validate_webhook_payload: Enable payload validation PR and Issue Settings: auto_link_issues: Automatically link issues in PRs require_issue_in_pr: Require issue reference in PRs allowed_pr_labels: Allowed labels for PRs auto_close_stale_prs: Auto close stale PRs stale_pr_days: Days before PR is considered stale GitHub Enterprise: is_enterprise: Whether using GitHub Enterprise enterprise_api_path: API path for Enterprise skip_ssl_verification: Skip SSL verification (not recommended) """ # API Settings api_base_url: HttpUrl = Field( default_factory=lambda: HttpUrl("https://api.github.com"), description="GitHub API base URL", ) api_version: str = Field( default="2022-11-28", description="GitHub API version (use YYYY-MM-DD format)" ) api_timeout_seconds: int = Field( default=30, ge=5, le=300, description="Timeout for API requests in seconds" ) max_retries: int = Field( default=3, ge=0, le=10, description="Maximum retry attempts for failed requests" ) retry_backoff_factor: float = Field( default=2.0, ge=1.0, le=5.0, description="Exponential backoff multiplier for retries", ) # Authentication api_token: str | None = Field( default=None, description="GitHub API token for authentication" ) token_scopes: list[str] = Field( default_factory=lambda: ["repo", "read:org"], description="Required GitHub token scopes", ) validate_token_on_startup: bool = Field( default=True, description="Validate token and scopes at startup" ) # Rate Limiting rate_limit_buffer: int = Field( default=100, ge=0, le=1000, description="Number of API requests to keep in reserve", ) rate_limit_threshold: float = Field( default=0.2, ge=0.0, le=0.5, description="Rate limit warning threshold (0.2 = warn at 20% remaining)", ) auto_retry_rate_limited: bool = Field( default=True, description="Automatically retry requests when rate limited" ) max_rate_limit_wait: int = Field( default=3600, ge=60, le=7200, description="Maximum seconds to wait for rate limit reset", ) # Webhook Configuration webhook_secret: str | None = Field( default=None, description="Secret for validating webhook payloads" ) allowed_webhook_events: list[str] = Field( default_factory=lambda: [ "push", "pull_request", "pull_request_review", "issues", "issue_comment", "workflow_run", ], description="List of allowed webhook event types", ) webhook_timeout: int = Field( default=30, ge=5, le=120, description="Timeout for webhook processing in seconds", ) validate_webhook_payload: bool = Field( default=True, description="Enable webhook payload signature validation" ) # PR and Issue Settings auto_link_issues: bool = Field( default=True, description="Automatically link mentioned issues in PRs" ) require_issue_in_pr: bool = Field( default=False, description="Require issue reference in PR description" ) allowed_pr_labels: list[str] = Field( default_factory=list, description="Allowed labels for PRs (empty = all allowed)" ) auto_close_stale_prs: bool = Field( default=False, description="Automatically close stale PRs" ) stale_pr_days: int = Field( default=30, ge=7, le=365, description="Days of inactivity before PR is considered stale", ) # GitHub Enterprise is_enterprise: bool = Field( default=False, description="Whether using GitHub Enterprise" ) enterprise_api_path: str = Field( default="/api/v3", description="API path for GitHub Enterprise" ) skip_ssl_verification: bool = Field( default=False, description="Skip SSL verification for Enterprise (not recommended)", ) @field_validator("api_token") @classmethod def validate_api_token(cls, v: str | None) -> str | None: """Validate GitHub API token format. Args: v: API token to validate Returns: Validated token Raises: ValueError: If token format is invalid """ if v is not None: # Check token format valid_prefixes = ("ghp_", "gho_", "ghu_", "ghs_", "ghr_", "github_pat_") if not any(v.startswith(prefix) for prefix in valid_prefixes): raise ValueError( f"Invalid GitHub token format. Token must start with one of: " f"{', '.join(valid_prefixes)}" ) # Check token length (approximate) if len(v) < 40: raise ValueError("GitHub token appears too short") return v @field_validator("api_version") @classmethod def validate_api_version(cls, v: str) -> str: """Validate GitHub API version format. Args: v: API version string Returns: Validated version string Raises: ValueError: If version format is invalid """ # Should be in YYYY-MM-DD format pattern = r"^\d{4}-\d{2}-\d{2}$" if not re.match(pattern, v): raise ValueError( "API version must be in YYYY-MM-DD format (e.g., '2022-11-28')" ) return v @field_validator("allowed_webhook_events") @classmethod def validate_webhook_events(cls, v: list[str]) -> list[str]: """Validate webhook event types. Args: v: List of webhook events Returns: Validated list of events Raises: ValueError: If invalid event type """ valid_events = { "branch_protection_rule", "check_run", "check_suite", "code_scanning_alert", "commit_comment", "create", "delete", "deployment", "deployment_status", "discussion", "discussion_comment", "fork", "gollum", "issue_comment", "issues", "label", "member", "membership", "milestone", "organization", "org_block", "page_build", "project", "project_card", "project_column", "public", "pull_request", "pull_request_review", "pull_request_review_comment", "pull_request_review_thread", "push", "registry_package", "release", "repository", "repository_dispatch", "secret_scanning_alert", "star", "status", "team", "team_add", "watch", "workflow_dispatch", "workflow_run", } invalid_events = set(v) - valid_events if invalid_events: raise ValueError( f"Invalid webhook events: {', '.join(invalid_events)}. " f"Valid events are: {', '.join(sorted(valid_events))}" ) return v @field_validator("token_scopes") @classmethod def validate_token_scopes(cls, v: list[str]) -> list[str]: """Validate GitHub token scopes. Args: v: List of token scopes Returns: Validated list of scopes Raises: ValueError: If invalid scope """ valid_scopes = { "repo", "repo:status", "repo_deployment", "public_repo", "repo:invite", "security_events", "admin:repo_hook", "write:repo_hook", "read:repo_hook", "admin:org", "write:org", "read:org", "admin:public_key", "write:public_key", "read:public_key", "admin:org_hook", "gist", "notifications", "user", "read:user", "user:email", "user:follow", "delete_repo", "write:discussion", "read:discussion", "write:packages", "read:packages", "delete:packages", "admin:gpg_key", "write:gpg_key", "read:gpg_key", "workflow", } # Check for invalid scopes invalid_scopes = [] for scope in v: # Handle scopes with colons base_scope = scope.split(":")[0] if base_scope not in valid_scopes and scope not in valid_scopes: invalid_scopes.append(scope) if invalid_scopes: raise ValueError(f"Invalid token scopes: {', '.join(invalid_scopes)}") return v @field_validator("webhook_secret") @classmethod def validate_webhook_secret(cls, v: str | None) -> str | None: """Validate webhook secret strength. Args: v: Webhook secret Returns: Validated secret Raises: ValueError: If secret is too weak """ if v is not None: if len(v) < 16: raise ValueError("Webhook secret must be at least 16 characters long") # Warn if secret appears weak if v.lower() in ["secret", "password", "webhook", "github"]: import warnings warnings.warn( "Webhook secret appears weak. Use a strong, random secret.", UserWarning, stacklevel=2, ) return v @field_validator("api_base_url", mode="after") @classmethod def validate_api_base_url(cls, v: HttpUrl) -> HttpUrl: """Validate and normalize API base URL. Args: v: API base URL Returns: Validated URL """ # HttpUrl normalizes URLs automatically, including trailing slashes # We'll accept the default behavior of HttpUrl return v model_config = { # Allow population by field name "populate_by_name": True, # Schema generation with examples "json_schema_extra": { "example": { "api_base_url": "https://api.github.com", "api_version": "2022-11-28", "api_timeout_seconds": 30, "max_retries": 3, "retry_backoff_factor": 2.0, "api_token": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "token_scopes": ["repo", "read:org"], "validate_token_on_startup": True, "rate_limit_buffer": 100, "rate_limit_threshold": 0.2, "auto_retry_rate_limited": True, "max_rate_limit_wait": 3600, "webhook_secret": "my-secure-webhook-secret-123", "allowed_webhook_events": ["push", "pull_request"], "webhook_timeout": 30, "validate_webhook_payload": True, "auto_link_issues": True, "require_issue_in_pr": False, "allowed_pr_labels": ["bug", "feature", "enhancement"], "auto_close_stale_prs": False, "stale_pr_days": 30, "is_enterprise": False, "enterprise_api_path": "/api/v3", "skip_ssl_verification": False, } }, }

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/MementoRC/mcp-git'

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