Skip to content

Commit c82d448

Browse files
committed
Add infra and deployed example
1 parent ea7fb18 commit c82d448

22 files changed

+1560
-5
lines changed

agents/agentframework_http.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
load_dotenv(override=True)
2727

2828
# Constants
29-
MCP_SERVER_URL = "http://localhost:8000/mcp/"
29+
MCP_SERVER_URL = os.getenv("MCP_SERVER_URL", "http://localhost:8000/mcp/")
3030

3131
# Configure chat client based on API_HOST
3232
API_HOST = os.getenv("API_HOST", "github")

agents/langchainv1_http.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,15 @@
2525
load_dotenv(override=True)
2626

2727
# Constants
28-
MCP_SERVER_URL = "http://localhost:8000/mcp/"
29-
AZURE_COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default"
28+
MCP_SERVER_URL = os.getenv("MCP_SERVER_URL", "http://localhost:8000/mcp/")
3029

3130
# Configure language model based on API_HOST
3231
API_HOST = os.getenv("API_HOST", "github")
3332

3433
if API_HOST == "azure":
3534
token_provider = azure.identity.get_bearer_token_provider(
3635
azure.identity.DefaultAzureCredential(),
37-
AZURE_COGNITIVE_SERVICES_SCOPE
36+
"https://cognitiveservices.azure.com/.default"
3837
)
3938
base_model = ChatOpenAI(
4039
model=os.environ.get("AZURE_OPENAI_CHAT_DEPLOYMENT"),

azure.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
2+
3+
name: python-mcp-demo
4+
metadata:
5+
6+
services:
7+
# Not using remoteBuild due to private endpoint usage
8+
aca:
9+
project: .
10+
language: docker
11+
host: containerapp
12+
docker:
13+
path: ./servers/Dockerfile
14+
context: .
15+
hooks:
16+
postprovision:
17+
posix:
18+
shell: sh
19+
run: ./infra/write_env.sh
20+
continueOnError: true

infra/aca.bicep

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
param name string
2+
param location string = resourceGroup().location
3+
param tags object = {}
4+
5+
param identityName string
6+
param containerAppsEnvironmentName string
7+
param containerRegistryName string
8+
param serviceName string = 'aca'
9+
param exists bool
10+
param openAiDeploymentName string
11+
param openAiEndpoint string
12+
param cosmosDbAccount string
13+
param cosmosDbDatabase string
14+
param cosmosDbContainer string
15+
16+
resource acaIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
17+
name: identityName
18+
location: location
19+
}
20+
21+
22+
module app 'core/host/container-app-upsert.bicep' = {
23+
name: '${serviceName}-container-app-module'
24+
params: {
25+
name: name
26+
location: location
27+
tags: union(tags, { 'azd-service-name': serviceName })
28+
identityName: acaIdentity.name
29+
exists: exists
30+
containerAppsEnvironmentName: containerAppsEnvironmentName
31+
containerRegistryName: containerRegistryName
32+
ingressEnabled: true
33+
env: [
34+
{
35+
name: 'AZURE_OPENAI_CHAT_DEPLOYMENT'
36+
value: openAiDeploymentName
37+
}
38+
{
39+
name: 'AZURE_OPENAI_ENDPOINT'
40+
value: openAiEndpoint
41+
}
42+
{
43+
name: 'RUNNING_IN_PRODUCTION'
44+
value: 'true'
45+
}
46+
{
47+
name: 'AZURE_CLIENT_ID'
48+
value: acaIdentity.properties.clientId
49+
}
50+
{
51+
name: 'AZURE_COSMOSDB_ACCOUNT'
52+
value: cosmosDbAccount
53+
}
54+
{
55+
name: 'AZURE_COSMOSDB_DATABASE'
56+
value: cosmosDbDatabase
57+
}
58+
{
59+
name: 'AZURE_COSMOSDB_CONTAINER'
60+
value: cosmosDbContainer
61+
}
62+
]
63+
targetPort: 8000
64+
}
65+
}
66+
67+
output identityPrincipalId string = acaIdentity.properties.principalId
68+
output name string = app.outputs.name
69+
output hostName string = app.outputs.hostName
70+
output uri string = app.outputs.uri
71+
output imageName string = app.outputs.imageName
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
param name string
2+
param location string = resourceGroup().location
3+
param tags object = {}
4+
5+
param customSubDomainName string = name
6+
param deployments array = []
7+
param kind string = 'OpenAI'
8+
param publicNetworkAccess string = 'Enabled'
9+
param sku object = {
10+
name: 'S0'
11+
}
12+
13+
resource account 'Microsoft.CognitiveServices/accounts@2023-05-01' = {
14+
name: name
15+
location: location
16+
tags: tags
17+
kind: kind
18+
properties: {
19+
customSubDomainName: customSubDomainName
20+
publicNetworkAccess: publicNetworkAccess
21+
}
22+
sku: sku
23+
}
24+
25+
@batchSize(1)
26+
resource deployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01' = [for deployment in deployments: {
27+
parent: account
28+
name: deployment.name
29+
properties: {
30+
model: deployment.model
31+
raiPolicyName: contains(deployment, 'raiPolicyName') ? deployment.raiPolicyName : null
32+
}
33+
sku: contains(deployment, 'sku') ? deployment.sku : {
34+
name: 'Standard'
35+
capacity: 20
36+
}
37+
}]
38+
39+
output endpoint string = account.properties.endpoint
40+
output id string = account.id
41+
output name string = account.name
42+
output location string = account.location
43+
output skuName string = account.sku.name
44+
output key string = account.listKeys().key1
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
param name string
2+
param location string = resourceGroup().location
3+
param tags object = {}
4+
5+
param containerAppsEnvironmentName string
6+
param containerName string = 'main'
7+
param containerRegistryName string
8+
9+
@description('Minimum number of replicas to run')
10+
@minValue(1)
11+
param containerMinReplicas int = 1
12+
@description('Maximum number of replicas to run')
13+
@minValue(1)
14+
param containerMaxReplicas int = 10
15+
16+
param secrets array = []
17+
param env array = []
18+
param external bool = true
19+
param targetPort int = 80
20+
param exists bool
21+
22+
@description('User assigned identity name')
23+
param identityName string
24+
25+
@description('Enabled Ingress for container app')
26+
param ingressEnabled bool = true
27+
28+
// Dapr Options
29+
@description('Enable Dapr')
30+
param daprEnabled bool = false
31+
@description('Dapr app ID')
32+
param daprAppId string = containerName
33+
@allowed([ 'http', 'grpc' ])
34+
@description('Protocol used by Dapr to connect to the app, e.g. http or grpc')
35+
param daprAppProtocol string = 'http'
36+
37+
@description('CPU cores allocated to a single container instance, e.g. 0.5')
38+
param containerCpuCoreCount string = '0.5'
39+
40+
@description('Memory allocated to a single container instance, e.g. 1Gi')
41+
param containerMemory string = '1.0Gi'
42+
43+
@description('Workload profile name to use for the container app when using private ingress')
44+
param workloadProfileName string = 'Warm'
45+
46+
resource existingApp 'Microsoft.App/containerApps@2022-03-01' existing = if (exists) {
47+
name: name
48+
}
49+
50+
module app 'container-app.bicep' = {
51+
name: '${deployment().name}-update'
52+
params: {
53+
name: name
54+
location: location
55+
tags: tags
56+
identityName: identityName
57+
ingressEnabled: ingressEnabled
58+
containerName: containerName
59+
containerAppsEnvironmentName: containerAppsEnvironmentName
60+
containerRegistryName: containerRegistryName
61+
containerCpuCoreCount: containerCpuCoreCount
62+
containerMemory: containerMemory
63+
containerMinReplicas: containerMinReplicas
64+
containerMaxReplicas: containerMaxReplicas
65+
daprEnabled: daprEnabled
66+
daprAppId: daprAppId
67+
daprAppProtocol: daprAppProtocol
68+
secrets: secrets
69+
external: external
70+
env: env
71+
imageName: exists ? existingApp.properties.template.containers[0].image : ''
72+
targetPort: targetPort
73+
// Pass workload profile name parameter
74+
workloadProfileName: workloadProfileName
75+
}
76+
}
77+
78+
output defaultDomain string = app.outputs.defaultDomain
79+
output imageName string = app.outputs.imageName
80+
output name string = app.outputs.name
81+
output hostName string = app.outputs.hostName
82+
output uri string = app.outputs.uri
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
param name string
2+
param location string = resourceGroup().location
3+
param tags object = {}
4+
5+
param containerAppsEnvironmentName string
6+
param containerName string = 'main'
7+
param containerRegistryName string
8+
9+
@description('Minimum number of replicas to run')
10+
@minValue(1)
11+
param containerMinReplicas int = 1
12+
@description('Maximum number of replicas to run')
13+
@minValue(1)
14+
param containerMaxReplicas int = 10
15+
16+
param secrets array = []
17+
param env array = []
18+
param external bool = true
19+
param imageName string
20+
param targetPort int = 80
21+
22+
@description('User assigned identity name')
23+
param identityName string
24+
25+
@description('Enabled Ingress for container app')
26+
param ingressEnabled bool = true
27+
28+
// Dapr Options
29+
@description('Enable Dapr')
30+
param daprEnabled bool = false
31+
@description('Dapr app ID')
32+
param daprAppId string = containerName
33+
@allowed([ 'http', 'grpc' ])
34+
@description('Protocol used by Dapr to connect to the app, e.g. http or grpc')
35+
param daprAppProtocol string = 'http'
36+
37+
@description('CPU cores allocated to a single container instance, e.g. 0.5')
38+
param containerCpuCoreCount string = '0.5'
39+
40+
@description('Memory allocated to a single container instance, e.g. 1Gi')
41+
param containerMemory string = '1.0Gi'
42+
43+
@description('Workload profile name to use for the container app when using private ingress')
44+
param workloadProfileName string = 'Warm'
45+
46+
resource userIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = {
47+
name: identityName
48+
}
49+
50+
module containerRegistryAccess '../security/registry-access.bicep' = {
51+
name: '${deployment().name}-registry-access'
52+
params: {
53+
containerRegistryName: containerRegistryName
54+
principalId: userIdentity.properties.principalId
55+
}
56+
}
57+
58+
resource app 'Microsoft.App/containerApps@2025-01-01' = {
59+
name: name
60+
location: location
61+
tags: tags
62+
// It is critical that the identity is granted ACR pull access before the app is created
63+
// otherwise the container app will throw a provision error
64+
// This also forces us to use an user assigned managed identity since there would no way to
65+
// provide the system assigned identity with the ACR pull access before the app is created
66+
dependsOn: [ containerRegistryAccess ]
67+
identity: {
68+
type: 'UserAssigned'
69+
userAssignedIdentities: { '${userIdentity.id}': {} }
70+
}
71+
properties: {
72+
managedEnvironmentId: containerAppsEnvironment.id
73+
configuration: {
74+
activeRevisionsMode: 'single'
75+
ingress: ingressEnabled ? {
76+
external: external
77+
targetPort: targetPort
78+
transport: 'auto'
79+
} : null
80+
dapr: daprEnabled ? {
81+
enabled: true
82+
appId: daprAppId
83+
appProtocol: daprAppProtocol
84+
appPort: ingressEnabled ? targetPort : 0
85+
} : { enabled: false }
86+
secrets: secrets
87+
registries: [
88+
{
89+
server: '${containerRegistry.name}.azurecr.io'
90+
identity: userIdentity.id
91+
}
92+
]
93+
}
94+
template: {
95+
containers: [
96+
{
97+
image: !empty(imageName) ? imageName : 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
98+
name: containerName
99+
env: env
100+
resources: {
101+
cpu: json(containerCpuCoreCount)
102+
memory: containerMemory
103+
}
104+
}
105+
]
106+
scale: {
107+
minReplicas: containerMinReplicas
108+
maxReplicas: containerMaxReplicas
109+
}
110+
}
111+
}
112+
}
113+
114+
resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-03-01' existing = {
115+
name: containerAppsEnvironmentName
116+
}
117+
118+
// 2022-02-01-preview needed for anonymousPullEnabled
119+
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' existing = {
120+
name: containerRegistryName
121+
}
122+
123+
output defaultDomain string = containerAppsEnvironment.properties.defaultDomain
124+
output imageName string = imageName
125+
output name string = app.name
126+
output hostName string = app.properties.configuration.ingress.fqdn
127+
output uri string = ingressEnabled ? 'https://${app.properties.configuration.ingress.fqdn}' : ''

0 commit comments

Comments
 (0)