Skip to main content
Glama

Azure DevOps MCP Server

by jhlia0
config.py5.96 kB
from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict from typing import Optional, List class AzureDevOpsSettings(BaseSettings): """Azure DevOps configuration settings loaded from environment variables.""" model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", case_sensitive=False, extra="ignore" ) # Azure DevOps configuration organization: str = Field(..., description="Azure DevOps organization name") project: str = Field(..., description="Azure DevOps project name") personal_access_token: str = Field(..., alias="AZURE_DEVOPS_PAT", description="Personal Access Token for Azure DevOps") # API configuration api_version: str = Field(default="7.1", description="Azure DevOps REST API version") base_url: str = Field(default="https://dev.azure.com", description="Azure DevOps base URL") # Default search settings default_team: Optional[str] = Field(default=None, description="Default team name for backlog queries") default_user: Optional[str] = Field(default=None, description="Default user for work item queries") default_work_item_types: str = Field(default="Bug,Task,User Story,Product Backlog Item", description="Default work item types (comma-separated)") default_max_results: int = Field(default=100, description="Default maximum number of results to return") # Search filters exclude_closed: bool = Field(default=True, description="Exclude closed work items by default") exclude_removed: bool = Field(default=True, description="Exclude removed work items by default") # Default iteration settings default_iteration_path: Optional[str] = Field(default=None, description="Default iteration path for queries") default_area_path: Optional[str] = Field(default=None, description="Default area path for queries") # State-specific settings default_active_states: str = Field(default="Active,New,In Progress,To Do,Doing", description="Default active states (comma-separated)") default_completed_states: str = Field(default="Closed,Done,Resolved", description="Default completed states (comma-separated)") default_review_states: str = Field(default="Code Review,Testing,Approved", description="Default review states (comma-separated)") # Project filtering settings enable_project_filtering: bool = Field(default=True, description="Enable project filtering in WIQL queries by default") @property def api_base_url(self) -> str: """Get the complete API base URL.""" return f"{self.base_url}/{self.organization}/{self.project}/_apis" @property def auth_header(self) -> dict[str, str]: """Get authentication header for API requests.""" import base64 token = base64.b64encode(f":{self.personal_access_token}".encode()).decode() return {"Authorization": f"Basic {token}"} @property def default_work_item_types_list(self) -> List[str]: """Get default work item types as a list.""" return [t.strip() for t in self.default_work_item_types.split(",")] @property def default_active_states_list(self) -> List[str]: """Get default active states as a list.""" return [s.strip() for s in self.default_active_states.split(",")] @property def default_completed_states_list(self) -> List[str]: """Get default completed states as a list.""" return [s.strip() for s in self.default_completed_states.split(",")] @property def default_review_states_list(self) -> List[str]: """Get default review states as a list.""" return [s.strip() for s in self.default_review_states.split(",")] def get_default_state_filter(self) -> str: """Get default state filter for WIQL queries.""" conditions = [] if self.exclude_closed: conditions.append("[System.State] <> 'Closed'") if self.exclude_removed: conditions.append("[System.State] <> 'Removed'") if conditions: return " AND " + " AND ".join(conditions) return "" def get_project_filter(self, project: str, force_filter: Optional[bool] = None) -> str: """Get project filter for WIQL queries. Args: project: Project name to filter by force_filter: Override the default project filtering setting Returns: Project filter string or empty string if filtering is disabled """ should_filter = force_filter if force_filter is not None else self.enable_project_filtering if should_filter and project: return f"[System.TeamProject] = '{project}'" return "" def get_default_wiql_filters(self, project: Optional[str] = None, include_project_filter: Optional[bool] = None) -> str: """Get default WIQL filters including state, iteration, area, and optionally project.""" filters = [] # State filters state_filter = self.get_default_state_filter() if state_filter: filters.append(state_filter.replace(" AND ", "", 1)) # Iteration path filter if self.default_iteration_path: filters.append(f"[System.IterationPath] UNDER '{self.default_iteration_path}'") # Area path filter if self.default_area_path: filters.append(f"[System.AreaPath] UNDER '{self.default_area_path}'") # Project filter if project: project_filter = self.get_project_filter(project, include_project_filter) if project_filter: filters.append(project_filter) if filters: return " AND " + " AND ".join(filters) return "" # Global settings instance settings = AzureDevOpsSettings()

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/jhlia0/azure-devops-mcp'

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