mahimairaja commited on
Commit
0bf5d52
·
1 Parent(s): bcc77c5

feat: added mcp server, and semantic kernal setup

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +1 -0
  2. README.md +56 -1
  3. data/configs.json +43 -0
  4. data/logs.json +122 -0
  5. data/templates/sql_scale.sh +12 -0
  6. data/templates/vm_resize.bicep +17 -0
  7. infra/__init__.py +0 -0
  8. infra/provision.py +0 -0
  9. pyproject.toml +2 -0
  10. scripts/generate_configs.py +52 -0
  11. scripts/generate_data.py +0 -0
  12. scripts/generate_logs.py +58 -0
  13. src/__init__.py +0 -0
  14. src/backend/agent/azure_agent.py +93 -0
  15. src/backend/agent/memory.py +0 -0
  16. src/backend/agent/planner.py +0 -0
  17. src/backend/agent/semantic_kernal.py +0 -0
  18. src/backend/app.py +39 -5
  19. src/backend/core/__init__.py +0 -0
  20. src/backend/core/config.py +0 -0
  21. src/backend/core/logger.py +0 -0
  22. src/backend/core/validators.py +0 -0
  23. src/backend/middleware/__init__.py +0 -0
  24. src/backend/middleware/auth.py +0 -0
  25. src/backend/models/__init__.py +0 -0
  26. src/backend/routes/__init__.py +0 -0
  27. src/backend/routes/chat.py +0 -0
  28. src/backend/routes/health.py +0 -0
  29. src/backend/routes/tools.py +0 -0
  30. src/backend/schemas/__init__.py +0 -0
  31. src/backend/services/mcp_client.py +10 -0
  32. src/frontend/app.py +31 -4
  33. src/mcp/Dockerfile +0 -1
  34. src/mcp/__init__.py +0 -0
  35. src/mcp/main.py +95 -0
  36. src/mcp/models/__init__.py +0 -0
  37. src/mcp/prompts/__init__.py +0 -0
  38. src/mcp/prompts/analyse_issue.py +0 -0
  39. src/mcp/prompts/explain_steps.py +0 -0
  40. src/mcp/prompts/suggest_remediation.py +0 -0
  41. src/mcp/resources/__init__.py +0 -0
  42. src/mcp/resources/alerts.py +0 -0
  43. src/mcp/resources/metrics.py +0 -0
  44. src/mcp/resources/templates.py +0 -0
  45. src/mcp/schemas/__init__.py +0 -0
  46. src/mcp/server.py +0 -13
  47. src/mcp/tests/test_mcp.py +46 -0
  48. src/mcp/tools/__init__.py +0 -0
  49. src/mcp/tools/config_reader.py +0 -0
  50. src/mcp/tools/fix_generator.py +0 -0
.gitignore CHANGED
@@ -6,6 +6,7 @@ __pycache__/
6
  # C extensions
7
  *.so
8
  uv.lock
 
9
 
10
  # Distribution / packaging
11
  .Python
 
6
  # C extensions
7
  *.so
8
  uv.lock
9
+ archieve
10
 
11
  # Distribution / packaging
12
  .Python
README.md CHANGED
@@ -1 +1,56 @@
1
- # azure-agent-ops-copilot
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Azure Ops Copilot
2
+
3
+ An agentic AI application that acts as a DevOps assistant for Azure. It uses the Azure Agent Framework, Semantic Kernel, and Model Context Protocol (MCP) to analyze alerts, inspect configurations, and suggest fixes.
4
+
5
+ ## Features
6
+
7
+ - **Log Analyzer**: Reads Azure Monitor alerts from synthetic logs.
8
+ - **Config Reader**: Inspects resource configurations (ARM/Bicep).
9
+ - **Fix Generator**: Suggests remediation steps (CLI/Bicep snippets).
10
+ - **Agentic Interface**: Chat with the copilot via a web UI.
11
+
12
+ ## Architecture
13
+
14
+ - **Backend**: FastAPI
15
+ - **Frontend**: Gradio
16
+ - **AI Engine**: Semantic Kernel + Azure OpenAI
17
+ - **Tools**: MCP Server (FastMCP)
18
+
19
+ ## Setup
20
+
21
+ 1. **Install Dependencies**:
22
+ ```bash
23
+ uv sync
24
+ ```
25
+
26
+ 2. **Configure Environment**:
27
+ Copy `.env.template` to `.env` (or create it) and add your Azure OpenAI keys.
28
+ ```bash
29
+ AZURE_OPENAI_ENDPOINT=...
30
+ AZURE_OPENAI_API_KEY=...
31
+ AZURE_OPENAI_DEPLOYMENT_NAME=...
32
+ ```
33
+
34
+ 3. **Generate Synthetic Data**:
35
+ ```bash
36
+ uv run python scripts/generate_logs.py
37
+ uv run python scripts/generate_configs.py
38
+ ```
39
+
40
+ 4. **Run the Application**:
41
+ Start the API:
42
+ ```bash
43
+ uv run python src/api/main.py
44
+ ```
45
+
46
+ Start the UI (in a separate terminal):
47
+ ```bash
48
+ uv run python src/ui/app.py
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ Open the Gradio UI (usually at `http://localhost:7860`) and ask questions like:
54
+ - "Analyze alert alert-001"
55
+ - "Check config for vm-01"
56
+ - "Suggest a fix for high CPU on vm-01"
data/configs.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-01",
4
+ "type": "Microsoft.Compute/virtualMachines",
5
+ "location": "eastus",
6
+ "properties": {
7
+ "hardwareProfile": {
8
+ "vmSize": "Standard_D2s_v3"
9
+ },
10
+ "storageProfile": {
11
+ "osDisk": {
12
+ "osType": "Linux",
13
+ "diskSizeGB": 30
14
+ }
15
+ }
16
+ },
17
+ "compliance_status": "Compliant"
18
+ },
19
+ {
20
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Sql/servers/sql-01/databases/db-01",
21
+ "type": "Microsoft.Sql/servers/databases",
22
+ "location": "eastus",
23
+ "properties": {
24
+ "sku": {
25
+ "name": "Standard",
26
+ "tier": "Standard",
27
+ "capacity": 10
28
+ },
29
+ "maxSizeBytes": 2147483648
30
+ },
31
+ "compliance_status": "NonCompliant"
32
+ },
33
+ {
34
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Web/sites/app-01",
35
+ "type": "Microsoft.Web/sites",
36
+ "location": "eastus",
37
+ "properties": {
38
+ "serverFarmId": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Web/serverfarms/plan-01",
39
+ "httpsOnly": false
40
+ },
41
+ "compliance_status": "NonCompliant"
42
+ }
43
+ ]
data/logs.json ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "id": "alert-001",
4
+ "severity": "Critical",
5
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Sql/servers/sql-01/databases/db-01",
6
+ "description": "High CPU usage detected (95%)",
7
+ "created_at": "2025-11-24T07:44:05.852238",
8
+ "status": "New",
9
+ "properties": {
10
+ "metric_value": 100,
11
+ "threshold": 80
12
+ }
13
+ },
14
+ {
15
+ "id": "alert-002",
16
+ "severity": "Critical",
17
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-01",
18
+ "description": "High CPU usage detected (95%)",
19
+ "created_at": "2025-11-24T07:40:05.852399",
20
+ "status": "New",
21
+ "properties": {
22
+ "metric_value": 86,
23
+ "threshold": 80
24
+ }
25
+ },
26
+ {
27
+ "id": "alert-003",
28
+ "severity": "Warning",
29
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Web/sites/app-01",
30
+ "description": "SQL Database DTU usage high (90%)",
31
+ "created_at": "2025-11-24T07:43:05.852404",
32
+ "status": "New",
33
+ "properties": {
34
+ "metric_value": 96,
35
+ "threshold": 80
36
+ }
37
+ },
38
+ {
39
+ "id": "alert-004",
40
+ "severity": "Warning",
41
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-01",
42
+ "description": "App Service response time high (>2s)",
43
+ "created_at": "2025-11-24T07:42:05.852407",
44
+ "status": "New",
45
+ "properties": {
46
+ "metric_value": 100,
47
+ "threshold": 80
48
+ }
49
+ },
50
+ {
51
+ "id": "alert-005",
52
+ "severity": "Critical",
53
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Sql/servers/sql-01/databases/db-01",
54
+ "description": "Disk space low (5% remaining)",
55
+ "created_at": "2025-11-24T07:19:05.852410",
56
+ "status": "New",
57
+ "properties": {
58
+ "metric_value": 90,
59
+ "threshold": 80
60
+ }
61
+ },
62
+ {
63
+ "id": "alert-006",
64
+ "severity": "Warning",
65
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Sql/servers/sql-01/databases/db-01",
66
+ "description": "SQL Database DTU usage high (90%)",
67
+ "created_at": "2025-11-24T07:36:05.852412",
68
+ "status": "New",
69
+ "properties": {
70
+ "metric_value": 97,
71
+ "threshold": 80
72
+ }
73
+ },
74
+ {
75
+ "id": "alert-007",
76
+ "severity": "Warning",
77
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-01",
78
+ "description": "App Service response time high (>2s)",
79
+ "created_at": "2025-11-24T06:50:05.852414",
80
+ "status": "New",
81
+ "properties": {
82
+ "metric_value": 91,
83
+ "threshold": 80
84
+ }
85
+ },
86
+ {
87
+ "id": "alert-008",
88
+ "severity": "Critical",
89
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-01",
90
+ "description": "High CPU usage detected (95%)",
91
+ "created_at": "2025-11-24T07:04:05.852417",
92
+ "status": "New",
93
+ "properties": {
94
+ "metric_value": 89,
95
+ "threshold": 80
96
+ }
97
+ },
98
+ {
99
+ "id": "alert-009",
100
+ "severity": "Critical",
101
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Web/sites/app-01",
102
+ "description": "High CPU usage detected (95%)",
103
+ "created_at": "2025-11-24T07:00:05.852419",
104
+ "status": "New",
105
+ "properties": {
106
+ "metric_value": 99,
107
+ "threshold": 80
108
+ }
109
+ },
110
+ {
111
+ "id": "alert-010",
112
+ "severity": "Critical",
113
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-01",
114
+ "description": "High CPU usage detected (95%)",
115
+ "created_at": "2025-11-24T07:03:05.852421",
116
+ "status": "New",
117
+ "properties": {
118
+ "metric_value": 93,
119
+ "threshold": 80
120
+ }
121
+ }
122
+ ]
data/templates/sql_scale.sh ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Scale SQL Database
3
+ RESOURCE_GROUP=$1
4
+ SERVER_NAME=$2
5
+ DB_NAME=$3
6
+ NEW_SKU=$4
7
+
8
+ az sql db update \
9
+ --resource-group $RESOURCE_GROUP \
10
+ --server $SERVER_NAME \
11
+ --name $DB_NAME \
12
+ --service-objective $NEW_SKU
data/templates/vm_resize.bicep ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ param vmName string
2
+ param location string = resourceGroup().location
3
+ param vmSize string = 'Standard_D4s_v3'
4
+
5
+ resource vm 'Microsoft.Compute/virtualMachines@2021-03-01' existing = {
6
+ name: vmName
7
+ }
8
+
9
+ resource vmUpdate 'Microsoft.Compute/virtualMachines@2021-03-01' = {
10
+ name: vmName
11
+ location: location
12
+ properties: {
13
+ hardwareProfile: {
14
+ vmSize: vmSize
15
+ }
16
+ }
17
+ }
infra/__init__.py DELETED
File without changes
infra/provision.py DELETED
File without changes
pyproject.toml CHANGED
@@ -9,6 +9,8 @@ dependencies = []
9
  [dependency-groups]
10
  backend = [
11
  "agent-framework>=1.0.0b251120",
 
 
12
  "semantic-kernel>=1.38.0",
13
  ]
14
  frontend = [
 
9
  [dependency-groups]
10
  backend = [
11
  "agent-framework>=1.0.0b251120",
12
+ "azure-ai-inference>=1.0.0b9",
13
+ "fastapi[standard]>=0.121.3",
14
  "semantic-kernel>=1.38.0",
15
  ]
16
  frontend = [
scripts/generate_configs.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from pathlib import Path
3
+
4
+ # Ensure data directory exists
5
+ DATA_DIR = Path(__file__).parent.parent / "data"
6
+ DATA_DIR.mkdir(exist_ok=True)
7
+
8
+ CONFIGS_FILE = DATA_DIR / "configs.json"
9
+
10
+ CONFIGS = [
11
+ {
12
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-01",
13
+ "type": "Microsoft.Compute/virtualMachines",
14
+ "location": "eastus",
15
+ "properties": {
16
+ "hardwareProfile": {"vmSize": "Standard_D2s_v3"},
17
+ "storageProfile": {"osDisk": {"osType": "Linux", "diskSizeGB": 30}},
18
+ },
19
+ "compliance_status": "Compliant",
20
+ },
21
+ {
22
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Sql/servers/sql-01/databases/db-01",
23
+ "type": "Microsoft.Sql/servers/databases",
24
+ "location": "eastus",
25
+ "properties": {
26
+ "sku": {"name": "Standard", "tier": "Standard", "capacity": 10},
27
+ "maxSizeBytes": 2147483648,
28
+ },
29
+ "compliance_status": "NonCompliant",
30
+ },
31
+ {
32
+ "resource_id": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Web/sites/app-01",
33
+ "type": "Microsoft.Web/sites",
34
+ "location": "eastus",
35
+ "properties": {
36
+ "serverFarmId": "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Web/serverfarms/plan-01",
37
+ "httpsOnly": False,
38
+ },
39
+ "compliance_status": "NonCompliant",
40
+ },
41
+ ]
42
+
43
+
44
+ def generate_configs():
45
+ with open(CONFIGS_FILE, "w") as f:
46
+ json.dump(CONFIGS, f, indent=2)
47
+
48
+ print(f"Generated {len(CONFIGS)} configs in {CONFIGS_FILE}")
49
+
50
+
51
+ if __name__ == "__main__":
52
+ generate_configs()
scripts/generate_data.py DELETED
File without changes
scripts/generate_logs.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import random
3
+ from datetime import datetime, timedelta
4
+ from pathlib import Path
5
+ from typing import Any, Dict, List
6
+
7
+ # Ensure data directory exists
8
+ DATA_DIR = Path(__file__).parent.parent / "data"
9
+ DATA_DIR.mkdir(exist_ok=True)
10
+
11
+ LOGS_FILE = DATA_DIR / "logs.json"
12
+
13
+ RESOURCE_IDS = [
14
+ "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-01",
15
+ "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Sql/servers/sql-01/databases/db-01",
16
+ "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Web/sites/app-01",
17
+ ]
18
+
19
+ ALERT_DESCRIPTIONS = [
20
+ "High CPU usage detected (95%)",
21
+ "Disk space low (5% remaining)",
22
+ "SQL Database DTU usage high (90%)",
23
+ "App Service response time high (>2s)",
24
+ ]
25
+
26
+
27
+ def generate_logs(count: int = 10):
28
+ logs: List[Dict[str, Any]] = []
29
+ for i in range(count):
30
+ resource_id = random.choice(RESOURCE_IDS)
31
+ description = random.choice(ALERT_DESCRIPTIONS)
32
+
33
+ # Determine severity based on description
34
+ severity = "Warning"
35
+ if "95%" in description or "5%" in description:
36
+ severity = "Critical"
37
+
38
+ log = {
39
+ "id": f"alert-{i + 1:03d}",
40
+ "severity": severity,
41
+ "resource_id": resource_id,
42
+ "description": description,
43
+ "created_at": (
44
+ datetime.now() - timedelta(minutes=random.randint(1, 60))
45
+ ).isoformat(),
46
+ "status": "New",
47
+ "properties": {"metric_value": random.randint(80, 100), "threshold": 80},
48
+ }
49
+ logs.append(log)
50
+
51
+ with open(LOGS_FILE, "w") as f:
52
+ json.dump(logs, f, indent=2)
53
+
54
+ print(f"Generated {count} logs in {LOGS_FILE}")
55
+
56
+
57
+ if __name__ == "__main__":
58
+ generate_logs()
src/__init__.py DELETED
File without changes
src/backend/agent/azure_agent.py CHANGED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import Annotated
3
+
4
+ from dotenv import load_dotenv
5
+ from semantic_kernel import Kernel
6
+ from semantic_kernel.agents import ChatCompletionAgent
7
+ from semantic_kernel.connectors.ai.function_choice_behavior import (
8
+ FunctionChoiceBehavior,
9
+ )
10
+ from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
11
+ from semantic_kernel.functions import kernel_function
12
+ from services.mcp_client import MCPClient
13
+
14
+ load_dotenv()
15
+ mcp_client = MCPClient()
16
+
17
+
18
+ class AzureOpsPlugin:
19
+ """Plugin wrapping our MCP tools for Semantic Kernel."""
20
+
21
+ @kernel_function(
22
+ name="analyze_alert", description="Analyze an Azure Monitor alert by ID."
23
+ )
24
+ def analyze_alert_wrapper(
25
+ self, alert_id: Annotated[str, "The ID of the alert to analyze"]
26
+ ) -> str:
27
+ return mcp_client.execute("analyze_alert", alert_id=alert_id)
28
+
29
+ @kernel_function(
30
+ name="get_resource_config",
31
+ description="Get the configuration of an Azure resource.",
32
+ )
33
+ def get_resource_config_wrapper(
34
+ self, resource_id: Annotated[str, "The ID of the resource"]
35
+ ) -> str:
36
+ return mcp_client.execute("get_resource_config", resource_id=resource_id)
37
+
38
+ @kernel_function(
39
+ name="generate_fix",
40
+ description="Generate a fix for a specific issue type and resource type.",
41
+ )
42
+ def generate_fix_wrapper(
43
+ self,
44
+ issue_type: Annotated[str, "The type of issue (e.g., 'High CPU')"],
45
+ resource_type: Annotated[str, "The type of resource"],
46
+ ) -> str:
47
+ return mcp_client.execute(
48
+ "generate_fix", issue_type=issue_type, resource_type=resource_type
49
+ )
50
+
51
+
52
+ async def get_agent() -> Kernel:
53
+ kernel = Kernel()
54
+
55
+ service_id = "default"
56
+ try:
57
+ kernel.add_service(
58
+ AzureChatCompletion(
59
+ service_id=service_id,
60
+ deployment_name=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4"),
61
+ endpoint=os.getenv("AZURE_OPENAI_ENDPOINT", ""),
62
+ api_key=os.getenv("AZURE_OPENAI_API_KEY", ""),
63
+ )
64
+ )
65
+ except Exception as e:
66
+ print(f"Warning: Could not configure Azure OpenAI: {e}")
67
+
68
+ kernel.add_plugin(AzureOpsPlugin(), plugin_name="AzureOps")
69
+
70
+ return kernel
71
+
72
+
73
+ async def get_chat_agent(kernel: Kernel) -> ChatCompletionAgent:
74
+ agent = ChatCompletionAgent(
75
+ kernel=kernel,
76
+ name="AzureOpsAgent",
77
+ instructions="You are an AI assistant that helps with Azure Operations. Use the available tools to analyze alerts and suggest fixes.",
78
+ function_choice_behavior=FunctionChoiceBehavior.Auto(),
79
+ )
80
+ return agent
81
+
82
+
83
+ async def run_agent(query: str):
84
+ kernel = await get_agent()
85
+ agent = await get_chat_agent(kernel)
86
+
87
+ # Execute the agent
88
+ final_response = []
89
+ async for response in agent.invoke(query):
90
+ if response.content:
91
+ final_response.append(response.content)
92
+
93
+ return "".join(final_response)
src/backend/agent/memory.py DELETED
File without changes
src/backend/agent/planner.py DELETED
File without changes
src/backend/agent/semantic_kernal.py DELETED
File without changes
src/backend/app.py CHANGED
@@ -1,8 +1,42 @@
1
- from fastapi import FastAPI
2
 
3
- app = FastAPI()
 
 
4
 
 
 
 
5
 
6
- @app.get("/")
7
- def read_root():
8
- return {"Details": "Azure Agent Ops Copilot"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
 
3
+ from agent.azure_agent import run_agent
4
+ from fastapi import FastAPI, HTTPException
5
+ from pydantic import BaseModel
6
 
7
+ # Configure logging
8
+ logging.basicConfig(level=logging.INFO)
9
+ logger = logging.getLogger(__name__)
10
 
11
+
12
+ app = FastAPI(title="Azure Ops Copilot API")
13
+
14
+
15
+ class ChatRequest(BaseModel):
16
+ message: str
17
+
18
+
19
+ class ChatResponse(BaseModel):
20
+ response: str
21
+
22
+
23
+ @app.post("/chat", response_model=ChatResponse)
24
+ async def chat(request: ChatRequest):
25
+ try:
26
+ logger.info(f"Received chat request: {request.message}")
27
+ result = await run_agent(request.message)
28
+ return ChatResponse(response=str(result))
29
+ except Exception as e:
30
+ logger.error(f"Error processing request: {e}")
31
+ raise HTTPException(status_code=500, detail=str(e))
32
+
33
+
34
+ @app.get("/health")
35
+ async def health():
36
+ return {"status": "healthy"}
37
+
38
+
39
+ if __name__ == "__main__":
40
+ import uvicorn
41
+
42
+ uvicorn.run(app, host="0.0.0.0", port=8000)
src/backend/core/__init__.py DELETED
File without changes
src/backend/core/config.py DELETED
File without changes
src/backend/core/logger.py DELETED
File without changes
src/backend/core/validators.py DELETED
File without changes
src/backend/middleware/__init__.py DELETED
File without changes
src/backend/middleware/auth.py DELETED
File without changes
src/backend/models/__init__.py DELETED
File without changes
src/backend/routes/__init__.py DELETED
File without changes
src/backend/routes/chat.py DELETED
File without changes
src/backend/routes/health.py DELETED
File without changes
src/backend/routes/tools.py DELETED
File without changes
src/backend/schemas/__init__.py DELETED
File without changes
src/backend/services/mcp_client.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastmcp import Client
2
+
3
+
4
+ class MCPClient:
5
+ def __init__(self):
6
+ self.mcp_path = "src/mcp/main.py"
7
+ self.client = Client(self.mcp_path)
8
+
9
+ def execute(self, tool_name, **kwargs):
10
+ return self.client.call_tool(tool_name, **kwargs)
src/frontend/app.py CHANGED
@@ -1,9 +1,36 @@
 
 
1
  import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- app = gr.Blocks()
 
 
 
 
 
 
 
 
4
 
5
- with app:
6
- gr.Markdown("# Azure Agent Ops Copilot")
7
 
8
  if __name__ == "__main__":
9
- app.launch()
 
1
+ import os
2
+
3
  import gradio as gr
4
+ import requests
5
+
6
+ API_URL = os.getenv("API_URL", "http://localhost:8000")
7
+
8
+
9
+ def chat(message, history):
10
+ try:
11
+ response = requests.post(f"{API_URL}/chat", json={"message": message})
12
+ response.raise_for_status()
13
+ return response.json()["response"]
14
+ except Exception as e:
15
+ return f"Error: {str(e)}"
16
+
17
+
18
+ with gr.Blocks(title="Azure Ops Copilot") as demo:
19
+ gr.Markdown("# 🤖 Azure Ops Copilot")
20
+ gr.Markdown(
21
+ "Your AI assistant for Azure DevOps. Ask me to analyze alerts, check configs, or suggest fixes."
22
+ )
23
 
24
+ chatbot = gr.ChatInterface(
25
+ fn=chat,
26
+ examples=[
27
+ "Analyze alert alert-001",
28
+ "Check config for vm-01",
29
+ "Suggest a fix for high CPU on vm-01",
30
+ ],
31
+ title="Chat with Copilot",
32
+ )
33
 
 
 
34
 
35
  if __name__ == "__main__":
36
+ demo.launch(server_name="0.0.0.0", server_port=7860)
src/mcp/Dockerfile DELETED
@@ -1 +0,0 @@
1
- FROM python:3.10-slim
 
 
src/mcp/__init__.py DELETED
File without changes
src/mcp/main.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastmcp import FastMCP
2
+ from utils import (
3
+ CONFIGS_FILE,
4
+ LOGS_FILE,
5
+ analyze_alert_logic,
6
+ generate_fix_logic,
7
+ get_resource_config_logic,
8
+ )
9
+
10
+ # Initialize FastMCP server
11
+ mcp = FastMCP("Azure Ops Copilot")
12
+
13
+ # --- Tools ---
14
+
15
+
16
+ @mcp.tool()
17
+ def analyze_alert(alert_id: str) -> str:
18
+ """
19
+ Analyze an Azure Monitor alert by ID.
20
+ Returns the alert details and potential root cause.
21
+ """
22
+ return analyze_alert_logic(alert_id)
23
+
24
+
25
+ @mcp.tool()
26
+ def get_resource_config(resource_id: str) -> str:
27
+ """
28
+ Get the configuration of an Azure resource.
29
+ """
30
+ return get_resource_config_logic(resource_id)
31
+
32
+
33
+ @mcp.tool()
34
+ def generate_fix(issue_type: str, resource_type: str) -> str:
35
+ """
36
+ Generate a fix for a specific issue type and resource type.
37
+ Returns a Bicep or CLI snippet.
38
+ """
39
+ return generate_fix_logic(issue_type, resource_type)
40
+
41
+
42
+ @mcp.tool()
43
+ def integration_placeholder(service_name: str, action: str) -> str:
44
+ """
45
+ Placeholder for future integrations (e.g., Jira, ServiceNow).
46
+ """
47
+ return (
48
+ f"Integration with {service_name} for action '{action}' is not yet implemented."
49
+ )
50
+
51
+
52
+ # --- Resources ---
53
+
54
+
55
+ @mcp.resource("azure://logs/recent")
56
+ def get_recent_logs() -> str:
57
+ """Get the most recent Azure Monitor logs."""
58
+ if LOGS_FILE.exists():
59
+ return LOGS_FILE.read_text()
60
+ return "[]"
61
+
62
+
63
+ @mcp.resource("azure://configs/all")
64
+ def get_all_configs() -> str:
65
+ """Get all resource configurations."""
66
+ if CONFIGS_FILE.exists():
67
+ return CONFIGS_FILE.read_text()
68
+ return "[]"
69
+
70
+
71
+ # --- Prompts ---
72
+
73
+
74
+ @mcp.prompt()
75
+ def analyze_issue(alert_id: str) -> str:
76
+ """Create a prompt to analyze an issue based on an alert ID."""
77
+ return f"""Please analyze the following alert and suggest remediation steps:
78
+ Alert ID: {alert_id}
79
+
80
+ 1. Use the 'analyze_alert' tool to get details.
81
+ 2. Use the 'get_resource_config' tool to check the resource configuration.
82
+ 3. Use the 'generate_fix' tool if a fix is applicable.
83
+ """
84
+
85
+
86
+ @mcp.prompt()
87
+ def suggest_fix(resource_id: str, issue: str) -> str:
88
+ """Create a prompt to suggest a fix for a resource."""
89
+ return f"""The resource {resource_id} is experiencing {issue}.
90
+ Please generate a fix using the available templates.
91
+ """
92
+
93
+
94
+ if __name__ == "__main__":
95
+ mcp.run()
src/mcp/models/__init__.py DELETED
File without changes
src/mcp/prompts/__init__.py DELETED
File without changes
src/mcp/prompts/analyse_issue.py DELETED
File without changes
src/mcp/prompts/explain_steps.py DELETED
File without changes
src/mcp/prompts/suggest_remediation.py DELETED
File without changes
src/mcp/resources/__init__.py DELETED
File without changes
src/mcp/resources/alerts.py DELETED
File without changes
src/mcp/resources/metrics.py DELETED
File without changes
src/mcp/resources/templates.py DELETED
File without changes
src/mcp/schemas/__init__.py DELETED
File without changes
src/mcp/server.py DELETED
@@ -1,13 +0,0 @@
1
- from fastmcp import FastMCP
2
-
3
- mcp = FastMCP("Azure AgentOps 🚀")
4
-
5
-
6
- @mcp.tool
7
- def add(a: int, b: int) -> int:
8
- """Add two numbers"""
9
- return a + b
10
-
11
-
12
- if __name__ == "__main__":
13
- mcp.run()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/mcp/tests/test_mcp.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ from pathlib import Path
3
+
4
+ sys.path.append(str(Path(__file__).parent.parent))
5
+
6
+ from src.mcp.logic import (
7
+ analyze_alert_logic,
8
+ generate_fix_logic,
9
+ get_resource_config_logic,
10
+ )
11
+
12
+
13
+ def test_analyze_alert():
14
+ print("Testing analyze_alert_logic...")
15
+ # Use a known ID from generation script logic (alert-001)
16
+ result = analyze_alert_logic("alert-001")
17
+ print(result)
18
+ assert "Alert Analysis" in result
19
+ assert "alert-001" in result
20
+
21
+
22
+ def test_get_resource_config():
23
+ print("\nTesting get_resource_config_logic...")
24
+ # Use a known ID from generation script
25
+ resource_id = "/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-01"
26
+ result = get_resource_config_logic(resource_id)
27
+ print(result)
28
+ assert "Standard_D2s_v3" in result
29
+
30
+
31
+ def test_generate_fix():
32
+ print("\nTesting generate_fix_logic...")
33
+ result = generate_fix_logic("High CPU", "Microsoft.Compute/virtualMachines")
34
+ print(result)
35
+ assert "vmSize" in result
36
+
37
+
38
+ if __name__ == "__main__":
39
+ try:
40
+ test_analyze_alert()
41
+ test_get_resource_config()
42
+ test_generate_fix()
43
+ print("\nAll tests passed!")
44
+ except Exception as e:
45
+ print(f"\nTest failed: {e}")
46
+ sys.exit(1)
src/mcp/tools/__init__.py DELETED
File without changes
src/mcp/tools/config_reader.py DELETED
File without changes
src/mcp/tools/fix_generator.py DELETED
File without changes