A configurable, production-ready GitHub Advanced Security for Azure DevOps (GHAzDO) MCP server for VS Code.
Automate security vulnerability detection and fix generation for any Azure DevOps project. Supports C#, TypeScript, and SQL with language-specific fix guidance tailored to team conventions.
✅ Simple Single-Project Config — One project at a time. Switch by editing .env.
✅ Language-Specific Fix Generation — C#, TypeScript, SQL handlers with team-aligned best practices
✅ Exact Code Context — Reads flagged lines directly from your local workspace
✅ Copilot-Ready Prompts — One-click security fix prompts ready for Copilot Chat
✅ Auto-Apply Mode — apply_fix produces a directive that makes Copilot edit the file in place, honouring .editorconfig and .github instructions
✅ Remediation Metrics — Track security improvement velocity (fix rate, introduced vs. fixed)
✅ Environment-Based Config — No hardcoding; works with any Azure DevOps org/project
# Clone or copy this folder to your workspace
cd mcp-advanced-security
# Install dependencies
pip install -r requirements.txt# Copy the template
cp .env.example .envEdit .env and fill in your Azure DevOps credentials:
AZDO_PAT=your-personal-access-token
AZDO_ORG=your-org
AZDO_PROJECT=your-project
AZDO_PROJECT_REPOS=repo1,repo2,repo3Important: Never commit .env — it is already listed in .gitignore.
Add to your workspace's .vscode/mcp.json (create if it doesn't exist):
{
"mcpServers": {
"mcp-advanced-security": {
"command": "python",
"args": [
"/path/to/Advanced.Security.MCP/server.py"
],
"env": {
"PYTHONPATH": "/path/to/Advanced.Security.MCP"
}
}
}
}Option A: Direct tool invocation
@mcp-advanced-security
list_alerts repository="mds.mapper.svc" alert_type="code" min_severity="high"
Option B: Via agent mode
@mcp-advanced-security
Use get_security_summary() to show the current security posture,
then list high-severity code alerts in mds.mapper.svc
# Personal Access Token (Scope: Advanced Security - Read)
# Get from: https://dev.azure.com/<org>/_usersSettings/tokens
AZDO_PAT=<your-pat>
# Organization name (from https://dev.azure.com/YOUR_ORG/)
AZDO_ORG=myorg
# Project name (from https://dev.azure.com/ORG/YOUR_PROJECT/)
AZDO_PROJECT=myproject
# Comma-separated list of repositories to monitor
AZDO_PROJECT_REPOS=repo1,repo2,repo3By default, the server auto-detects repo paths from sibling folders. To override:
AZDO_REPO_PATH_MDS_MAPPER_SVC=c:\path\to\mds.mapper.svc
AZDO_REPO_PATH_MDS_MAPPER_UI=c:\path\to\mds.mapper.uiVariable name pattern: AZDO_REPO_PATH_<REPO_NAME_UPPER_WITH_UNDERSCORES> (replace . and - with _).
Point to team coding standards for language-specific fix guidance:
INSTRUCTION_FILE_CSHARP=.github/instructions/dotnet-code-quality.instructions.md
INSTRUCTION_FILE_TYPESCRIPT=.github/instructions/angular-code-quality.instructions.md
INSTRUCTION_FILE_SQL=.github/copilot-instructions.mdTo switch to a different Azure DevOps project, just edit .env with the new values. No multi-project setup, no project_id parameters — keep separate .env files per project if you need to swap between them.
Get alert counts across all repos by severity and type.
Args:
branch(optional): Filter by branch (e.g., "develop", "main", "all")
Example:
get_security_summary branch="develop"
Output: Markdown table with counts by severity and alert type.
List active alerts for a repository with filtering.
Args:
repository: Repo name (e.g., "mds.mapper.svc")alert_type(optional): "code", "dependency", "secret", "all"min_severity(optional): "critical", "high", "medium", "low" (default: "high")branch(optional): Git branch filter
Example:
list_alerts repository="mds.mapper.svc" alert_type="code" min_severity="high"
Output: Numbered list with alert ID, severity, type, file location, and title.
Get full details for a specific alert.
Args:
repository: Repo namealert_id: Alert ID (from list_alerts output)
Example:
get_alert_details repository="mds.mapper.svc" alert_id="12345"
Output: Full vulnerability description, rule info, CWE tags, affected locations.
Generate a Copilot-ready fix prompt with exact code context.
Args:
repository: Repo namealert_id: Alert ID
Example:
get_fix_context repository="mds.mapper.svc" alert_id="12345"
Output:
- Full vulnerability explanation
- Exact flagged lines from your workspace (with
>>>markers) - Language-specific fix guidance (C#, TypeScript, SQL)
- Team convention reference
- Prompt for Copilot to generate the fix
Then use Copilot to generate the fix based on this prompt.
Like get_fix_context, but returns a directive prompt that tells Copilot to edit the workspace file in place. Refuses to run on alerts that are not in the active state.
Args:
repository: Repo namealert_id: Alert ID
Example:
apply_fix repository="mds.mapper.svc" alert_id="12345"
Output:
- All the context from
get_fix_context(vulnerability, flagged lines, language guidance) - The repo's
.editorconfig(and any nested overrides above the flagged file) - Matching
.github/instructions/*.instructions.md, plus.github/copilot-instructions.md/AGENTS.md - An imperative “Apply Now” block that constrains Copilot to: edit only the flagged lines, preserve method signatures, add a security-rationale comment referencing the alert id, run
dotnet build/npm run lintif available, and produce a diff
Refusal behaviour: if the alert is fixed, dismissed, or autodismissed, the tool returns a short message and does not emit a fix directive. Re-open the alert in Azure DevOps if you believe it’s incorrectly closed.
Track security remediation velocity over time.
Args:
days(optional): Look back period (default 30 for sprint cycle)
Example:
get_metrics_report days=30
Output: Table showing:
- Alerts introduced, fixed, dismissed
- Fix rate %
- Net change
- Currently active by type/severity
Advanced.Security.MCP/
├── server.py # FastMCP server entry point
├── config.py # Single-project config manager
├── setup.py # Setup & validation script
├── requirements.txt # Dependencies
├── .env.example # Configuration template
├── core/
│ ├── api_client.py # GHAzDO REST API wrapper
│ ├── alert_parser.py # Alert extraction & formatting
│ └── file_reader.py # Local file reading with context
├── language_handlers/
│ ├── __init__.py # HandlerManager (dispatch by file ext)
│ ├── base_handler.py # Base handler abstraction
│ ├── csharp_handler.py # C# fix generation
│ ├── typescript_handler.py # TypeScript/Angular fix generation
│ └── sql_handler.py # SQL fix generation
└── tools/
├── security_summary.py # Tool 1
├── list_alerts.py # Tool 2
├── alert_details.py # Tool 3
├── fix_context.py # Tool 4 (uses language handlers)
├── apply_fix.py # Tool 5 (active-alert directive, embeds repo conventions)
└── metrics_report.py # Tool 6
- Uses Clean Architecture patterns
- Dependency injection for mocking/testing
- Parameterized queries for SQL injection prevention
- Null-coalescing operators, pattern matching
- Logging and error handling conventions
- RxJS best practices (unsubscribe, takeUntil)
- @AutoUnsubscribe decorator for component lifecycle
- Angular component pattern compliance
- Prettier code style enforcement
- MSAL authentication patterns
- DomSanitizer for XSS prevention
- Parameterized queries (prepared statements)
- SQL Server @parameter syntax
- Connection string management via Key Vault
- Managed Identity for Azure auth
- Stored procedure input validation
To add support for a new language (e.g., Python, Java):
-
Create a handler:
# language_handlers/python_handler.py from language_handlers.base_handler import BaseLanguageHandler class PythonLanguageHandler(BaseLanguageHandler): def supports_language(self, file_path: str) -> bool: return file_path.endswith(".py") def get_fix_guidance(self, alert, file_path, alert_type): # Python-specific guidance return "..."
-
Register in HandlerManager:
# language_handlers/__init__.py from language_handlers.python_handler import PythonLanguageHandler class HandlerManager: def __init__(self, project_config): self.handlers = [ # ... PythonLanguageHandler(project_config), ]
-
Done! The new handler is automatically used by
get_fix_context.
-
.envfile created and filled in -
.envlisted in.gitignore(already done) -
.vscode/mcp.jsonconfigured - VS Code reloaded
- Run
python setup.pyto validate - Test:
get_security_summary()returns data - Test:
list_alerts()returns alerts - Test:
get_fix_context()generates prompt - Instruction files (if configured) are accessible
- Local repo paths auto-detect correctly
Check that AZDO_PAT, AZDO_ORG, AZDO_PROJECT, and AZDO_PROJECT_REPOS are all set in .env.
- Verify
AZDO_PATis correct - Check PAT scopes: must include "Advanced Security: Read"
- Verify
AZDO_ORGandAZDO_PROJECTmatch your Azure DevOps URL exactly
- Check
AZDO_REPO_PATH_*env var is set correctly - Verify repo path matches local workspace structure
- Check
.vscode/mcp.jsonis correctly formatted - Verify server.py path is absolute
- Reload VS Code after
.vscode/mcp.jsonchanges - Check VS Code output panel for startup errors
To improve language-specific guidance:
- Edit the appropriate handler (e.g.,
language_handlers/csharp_handler.py) - Update
get_fix_guidance()with better recommendations - Test with
get_fix_context()
MIT — Use freely. See LICENSE for details.
For issues or feature requests, contact the security team or file an issue in the repository.