Skip to content

Commit 2ef6e8b

Browse files
added the mcp server local support and changed backend pyproject.toml to have all the packages required
1 parent c204dfb commit 2ef6e8b

File tree

7 files changed

+2006
-162
lines changed

7 files changed

+2006
-162
lines changed

azure_custom.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ services:
1313
docker:
1414
image: backend
1515
remoteBuild: true
16+
17+
mcp:
18+
project: ./src/mcp_server
19+
language: py
20+
host: containerapp
21+
docker:
22+
image: mcp
23+
remoteBuild: true
1624

1725
frontend:
1826
project: ./src/frontend

infra/main.bicep

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,7 @@ module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = if (contai
10951095
systemAssigned: true
10961096
userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId]
10971097
}
1098-
ingressTargetPort: containerAppConfiguration.?ingressTargetPort ?? 8000
1098+
ingressTargetPort: 9000
10991099
ingressExternal: true
11001100
activeRevisionsMode: 'Single'
11011101
corsPolicy: {
@@ -1122,7 +1122,7 @@ module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = if (contai
11221122
containers: [
11231123
{
11241124
name: 'mcp'
1125-
image: 'macaemcpacrdk.azurecr.io/macae-mac-app:t7' //'${containerAppConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${containerAppConfiguration.?containerImageName ?? 'macaebackend'}:${containerAppConfiguration.?containerImageTag ?? 'latest'}'
1125+
image: 'macaemcpacrdk.azurecr.io/macae-mac-app:t9' //'${containerAppConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${containerAppConfiguration.?containerImageName ?? 'macaebackend'}:${containerAppConfiguration.?containerImageTag ?? 'latest'}'
11261126
resources: {
11271127
//TODO: Make cpu and memory parameterized
11281128
cpu: containerAppConfiguration.?containerCpu ?? '2.0'

infra/main.json

Lines changed: 1845 additions & 151 deletions
Large diffs are not rendered by default.

infra/main_custom.bicep

Lines changed: 142 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ param existingLogAnalyticsWorkspaceId string = ''
2020

2121
param azureopenaiVersion string = '2025-01-01-preview'
2222

23+
//Get the current deployer's information
24+
var deployerInfo = deployer()
25+
var deployingUserPrincipalId = deployerInfo.objectId
26+
2327
// Restricting deployment to only supported Azure OpenAI regions validated with GPT-4o model
2428
@metadata({
2529
azd : {
@@ -812,6 +816,36 @@ module cogServiceRoleAssignmentsExisting './modules/role.bicep' = if(useExisting
812816
scope: resourceGroup( split(existingFoundryProjectResourceId, '/')[2], split(existingFoundryProjectResourceId, '/')[4])
813817
}
814818

819+
// User Role Assignment for Azure OpenAI - New Resources
820+
module userOpenAiRoleAssignment './modules/role.bicep' = if (aiFoundryAIservicesEnabled && !useExistingResourceId) {
821+
name: take('user-openai-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}', 64)
822+
params: {
823+
name: 'user-openai-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}'
824+
principalId: deployingUserPrincipalId
825+
aiServiceName: aiFoundryAiServices.outputs.name
826+
principalType: 'User'
827+
}
828+
scope: resourceGroup(subscription().subscriptionId, resourceGroup().name)
829+
dependsOn: [
830+
aiFoundryAiServices
831+
]
832+
}
833+
834+
// User Role Assignment for Azure OpenAI - Existing Resources
835+
module userOpenAiRoleAssignmentExisting './modules/role.bicep' = if (aiFoundryAIservicesEnabled && useExistingResourceId) {
836+
name: take('user-openai-existing-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}', 64)
837+
params: {
838+
name: 'user-openai-existing-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}'
839+
principalId: deployingUserPrincipalId
840+
aiServiceName: aiFoundryAiServices.outputs.name
841+
principalType: 'User'
842+
}
843+
scope: resourceGroup(split(existingFoundryProjectResourceId, '/')[2], split(existingFoundryProjectResourceId, '/')[4])
844+
dependsOn: [
845+
aiFoundryAiServices
846+
]
847+
}
848+
815849
// ========== Cosmos DB ========== //
816850
// WAF best practices for Cosmos DB: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/cosmos-db
817851
module privateDnsZonesCosmosDb 'br/public:avm/res/network/private-dns-zone:0.7.0' = if (virtualNetworkEnabled) {
@@ -886,9 +920,10 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.12.0' = if (co
886920
capabilitiesToAdd: [
887921
'EnableServerless'
888922
]
889-
sqlRoleAssignmentsPrincipalIds: [
890-
containerApp.outputs.?systemAssignedMIPrincipalId
891-
]
923+
sqlRoleAssignmentsPrincipalIds: concat(
924+
[containerApp.outputs.?systemAssignedMIPrincipalId],
925+
[deployingUserPrincipalId]
926+
)
892927
sqlRoleDefinitions: [
893928
{
894929
// Replace this with built-in role definition Cosmos DB Built-in Data Contributor: https://docs.azure.cn/en-us/cosmos-db/nosql/security/reference-data-plane-roles#cosmos-db-built-in-data-contributor
@@ -1079,6 +1114,110 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container
10791114
}
10801115
}
10811116

1117+
1118+
var containerAppMcpResourceName = 'ca-mcp-${solutionPrefix}'
1119+
module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = if (containerAppEnabled) {
1120+
name: take('avm.res.app.container-app.${containerAppMcpResourceName}', 64)
1121+
params: {
1122+
name: containerAppMcpResourceName
1123+
tags: union(tags, { 'azd-service-name': 'mcp' })
1124+
location: containerAppConfiguration.?location ?? solutionLocation
1125+
enableTelemetry: enableTelemetry
1126+
environmentResourceId: containerAppConfiguration.?environmentResourceId ?? containerAppEnvironment.outputs.resourceId
1127+
managedIdentities: {
1128+
systemAssigned: true
1129+
userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId]
1130+
}
1131+
ingressTargetPort: 9000
1132+
ingressExternal: true
1133+
activeRevisionsMode: 'Single'
1134+
corsPolicy: {
1135+
allowedOrigins: [
1136+
'https://${webSiteName}.azurewebsites.net'
1137+
'http://${webSiteName}.azurewebsites.net'
1138+
]
1139+
}
1140+
// WAF aligned configuration for Scalability
1141+
scaleSettings: {
1142+
maxReplicas: containerAppConfiguration.?maxReplicas ?? 1
1143+
minReplicas: containerAppConfiguration.?minReplicas ?? 1
1144+
rules: [
1145+
{
1146+
name: 'http-scaler'
1147+
http: {
1148+
metadata: {
1149+
concurrentRequests: containerAppConfiguration.?concurrentRequests ?? '100'
1150+
}
1151+
}
1152+
}
1153+
]
1154+
}
1155+
registries: [
1156+
{
1157+
server: containerRegistry.outputs.loginServer
1158+
identity: userAssignedIdentity.outputs.resourceId
1159+
}
1160+
]
1161+
containers: [
1162+
{
1163+
name: 'mcp'
1164+
image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' //'${containerAppConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${containerAppConfiguration.?containerImageName ?? 'macaebackend'}:${containerAppConfiguration.?containerImageTag ?? 'latest'}'
1165+
resources: {
1166+
//TODO: Make cpu and memory parameterized
1167+
cpu: containerAppConfiguration.?containerCpu ?? '2.0'
1168+
memory: containerAppConfiguration.?containerMemory ?? '4.0Gi'
1169+
}
1170+
env: [
1171+
{
1172+
name: 'MCP_HOST'
1173+
value: '0.0.0.0'
1174+
}
1175+
{
1176+
name: 'MCP_PORT'
1177+
value: '9000'
1178+
}
1179+
{
1180+
name: 'MCP_DEBUG'
1181+
value: 'false'
1182+
}
1183+
{
1184+
name: 'MCP_SERVER_NAME'
1185+
value: 'MACAE MCP Server'
1186+
}
1187+
{
1188+
name: 'MCP_ENABLE_AUTH'
1189+
value: 'true'
1190+
}
1191+
{
1192+
name: 'AZURE_TENANT_ID'
1193+
value: tenant().tenantId
1194+
}
1195+
{
1196+
name: 'AZURE_CLIENT_ID'
1197+
value: userAssignedIdentity!.outputs.clientId
1198+
}
1199+
{
1200+
name: 'AZURE_JWKS_URI'
1201+
value: 'https://login.microsoftonline.com/${tenant().tenantId}/discovery/v2.0/keys'
1202+
}
1203+
{
1204+
name: 'AZURE_ISSUER'
1205+
value: 'https://sts.windows.net/${tenant().tenantId}/'
1206+
}
1207+
{
1208+
name: 'AZURE_AUDIENCE'
1209+
value: 'api://${userAssignedIdentity!.outputs.clientId}'
1210+
}
1211+
{
1212+
name: 'DATASET_PATH'
1213+
value: './datasets'
1214+
}
1215+
]
1216+
}
1217+
]
1218+
}
1219+
}
1220+
10821221
var webServerFarmEnabled = webServerFarmConfiguration.?enabled ?? true
10831222
var webServerFarmResourceName = webServerFarmConfiguration.?name ?? 'asp-${solutionPrefix}'
10841223

src/backend/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ dependencies = [
3131
"uvicorn>=0.34.2",
3232
"pylint-pydantic>=0.3.5",
3333
"pexpect>=4.9.0",
34+
"fastmcp==2.11.3",
3435
]

src/backend/v3/common/services/foundry_service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from typing import Any, Dict
1+
from typing import Any, Dict, List
22
import logging
33
import re
44
from azure.ai.projects.aio import AIProjectClient
5-
from git import List
5+
#from git import List
66
import aiohttp
77
from common.config.app_config import config
88

src/mcp_server/Dockerfile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
1111
COPY uv.lock pyproject.toml /app/
1212

1313
# Install dependencies (frozen, no dev) using uv
14-
RUN --mount=type=cache,target=/root/.cache/uv \
15-
uv sync --frozen --no-install-project --no-dev
14+
# RUN --mount=type=cache,target=/root/.cache/uv \
15+
# uv sync --frozen --no-install-project --no-dev
1616

17+
RUN uv sync --frozen --no-install-project --no-dev
1718
# Copy application code and install project dependencies
1819
COPY . /app
19-
RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen --no-dev
20+
#RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen --no-dev
21+
RUN uv sync --frozen --no-dev
2022

2123
# Final stage
2224
FROM base
@@ -40,4 +42,4 @@ HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
4042
CMD curl -f http://localhost:9000/health || exit 1
4143

4244
# Run your main script
43-
CMD ["uv", "run", "python", "mcp_server.py", "--transport", "http", "--host", "0.0.0.0", "--port", "9000"]
45+
CMD ["uv", "run", "python", "mcp_server.py", "--transport", "http", "--host", "0.0.0.0", "--port", "9000"]

0 commit comments

Comments
 (0)