IMPORTANT! All samples and other resources made available in this GitHub repository ("samples") are designed to assist in accelerating development of agents, solutions, and agent workflows for various scenarios. Review all provided resources and carefully test output behavior in the context of your use case. AI responses may be inaccurate and AI actions should be monitored with human oversight. Learn more in the transparency documents for Agent Service and Agent Framework.
Agents, solutions, or other output you create may be subject to legal and regulatory requirements, may require licenses, or may not be suitable for all industries, scenarios, or use cases. By using any sample, you are acknowledging that any output created using those samples are solely your responsibility, and that you will comply with all applicable laws, regulations, and relevant safety standards, terms of service, and codes of conduct.
Third-party samples contained in this folder are subject to their own designated terms, and they have not been tested or verified by Microsoft or its affiliates.
Microsoft has no responsibility to you or others with respect to any of these samples or any resulting output.
A LangGraph ReAct agent that connects to an toolbox in Microsoft Foundry via MCP and serves responses over the Foundry Responses Protocol.
- On startup the agent calls
client.get_tools()against the Toolbox MCP endpoint. - A
create_react_agentis built from the loaded tools and an Azure OpenAI LLM. - Incoming requests are handled by
ResponsesAgentServerHoston port8088. - The agent is initialized lazily (once, on the first request) and reused for all subsequent turns — the MCP client is kept alive to prevent session garbage-collection.
- When the toolbox requires OAuth consent (e.g. a GitHub connection that hasn't been
authorized yet), the MCP server returns error code
-32006. The agent detects this, logs the consent URL, and surfaces it to the caller via a fallback tool instead of crashing.
-
Python 3.12+
-
A Microsoft Foundry project with a toolbox already created — see
../sample_toolboxes_crud.pyto create one -
Azure CLI installed and logged in:
az login
Linux/macOS:
# 1. Copy and fill in the environment file
cp .env.example .env # skip if .env already exists
# Edit .env — set FOUNDRY_PROJECT_ENDPOINT, MODEL_DEPLOYMENT_NAME,
# and TOOLBOX_ENDPOINT at minimum
# 2. Install dependencies
pip install -r requirements.txt
# 3. Start the agent
python main.py
# 4. Invoke
curl -X POST http://localhost:8088/responses \
-H "Content-Type: application/json" \
-d '{"input": "What tools do you have?"}'Windows (PowerShell):
# 1. Copy and fill in the environment file
Copy-Item .env.example .env # skip if .env already exists
# Edit .env — set FOUNDRY_PROJECT_ENDPOINT, MODEL_DEPLOYMENT_NAME,
# and TOOLBOX_ENDPOINT at minimum
# 2. Install dependencies
pip install -r requirements.txt
# 3. Start the agent
python main.py
# 4. Invoke
Invoke-RestMethod -Method POST http://localhost:8088/responses `
-ContentType "application/json" `
-Body '{"input": "What tools do you have?"}'Linux/macOS:
curl -fsSL https://aka.ms/install-azd.sh | bashWindows (PowerShell):
winget install microsoft.azdSee the full installation docs for other options.
azd extension install azure.ai.agentsTo upgrade the extension later:
azd extension upgrade azure.ai.agentsazd auth logingit config --global core.autocrlf falseIMPORTANT: The
-m(or--manifest) flag is required forazd ai agent init. It tells the command where to find your agent definition and source files.
-mcan point to either:
- A specific
agent.manifest.yamlfile — init copies all files from the same directory as the manifest- A folder containing
agent.manifest.yaml— init copies all files from that folder
# 1. Create a new directory and initialize the agent project
mkdir my-langgraph-agent && cd my-langgraph-agent
PROJECT_ID="/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.CognitiveServices/accounts/<account>/projects/<project>"
azd ai agent init \
-m /path/to/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox/agent.manifest.yaml \
--project-id $PROJECT_ID \
--no-prompt \
-e my-env
# 2. Set required environment variables
azd env set enableHostedAgentVNext "true" -e my-env
azd env set AZURE_AI_MODEL_DEPLOYMENT_NAME "gpt-4o" -e my-env # must match the deployment name in azure.yaml
# 3. Provision infrastructure and deploy the container
azd up -e my-env
# 4. Invoke the deployed agent (run from the scaffolded project directory)
azd ai agent invoke --new-session "What tools do you have?" --timeout 120After azd ai agent init, perform these steps before azd up will work:
| # | Action | Why |
|---|---|---|
| 1 | azd env set enableHostedAgentVNext "true" |
Without this, container health probes fail |
| 2 | Edit src/<agent>/agent.yaml: replace all ${{VAR}} with ${VAR} |
Init scaffolds broken double-brace syntax that is NOT resolved at deploy time |
| 3 | Verify agent.yaml uses flat format (kind: hosted at root) |
The nested template: format silently fails during deploy |
| 4 | azd env set AZURE_AI_MODEL_DEPLOYMENT_NAME "<deployment-name>" |
Must match the deployment name in azure.yaml; platform injection is unreliable without this (container crashes on startup) |
| 5 | Verify main.py checks FOUNDRY_PROJECT_ENDPOINT first |
Platform injects this var, NOT AZURE_AI_PROJECT_ENDPOINT |
| 6 | If using existing project with AppInsights already connected: azd env set ENABLE_MONITORING "false" |
Provision fails with duplicate App Insights connection error |
| 7 | If model region ≠ RG region: edit generated infra/main.parameters.json — change aiDeploymentsLocation value from ${AZURE_LOCATION} to ${AZURE_AI_DEPLOYMENTS_LOCATION}, then azd env set AZURE_AI_DEPLOYMENTS_LOCATION "<region>" |
Init templates map model deployment location to AZURE_LOCATION which is wrong when model is in a different region |
azd ai agent init copies all source files (main.py, Dockerfile, requirements.txt, etc.) verbatim from the manifest directory into src/<agent-name>/ in the scaffolded project. It does NOT generate or modify main.py — it copies the exact file from your manifest.
The init command also:
- Creates
azure.yamlwith service config, connections, and toolbox definitions - Creates
infra/directory with Bicep templates - Creates
.azure/<env>/.envwith environment variables
After azd ai agent init, you get:
my-project/
├── .azure/
│ └── <env-name>/
│ ├── .env # Environment variables (auto-populated by azd)
│ └── config.json # Subscription + location config
├── infra/
│ ├── main.bicep # Top-level Bicep template
│ ├── main.parameters.json # Parameters (references .env values)
│ └── core/ai/
│ ├── ai-project.bicep # Project + connection deployment
│ └── connection.bicep # Connection resource template
├── src/
│ └── <agent-name>/
│ ├── agent.yaml # Agent definition (env vars, protocols)
│ ├── main.py # Agent code
│ ├── Dockerfile # Container build
│ └── requirements.txt # Dependencies
└── azure.yaml # azd service + toolbox configuration
Tip:
azd ai agent invokemust be run from the scaffolded project directory (the directory whereazure.yamlwas created byazd ai agent init).
The--timeout 120flag is recommended — agent cold starts can take up to 60 seconds.
| Variable | Required | Description |
|---|---|---|
FOUNDRY_PROJECT_ENDPOINT |
Yes | Project endpoint URL — platform-injected at runtime |
MODEL_DEPLOYMENT_NAME |
Yes | Model deployment name (e.g. gpt-4.1) |
TOOLBOX_ENDPOINT |
Yes | Full toolbox MCP endpoint URL including toolbox name and api-version |
FOUNDRY_AGENT_TOOLBOX_FEATURES |
No | Feature-flag header value — platform-injected (default: Toolboxes=V1Preview) |
TOOLBOX_ENDPOINT is the full pre-constructed MCP URL. Two forms are supported:
# Latest version:
https://<account>.services.ai.azure.com/api/projects/<project>/toolboxes/<name>/mcp?api-version=v1
# Pinned to a specific version:
https://<account>.services.ai.azure.com/api/projects/<project>/toolboxes/<name>/versions/<version>/mcp?api-version=v1
The version number is the integer toolbox version (e.g. 1). Use the versioned form to pin to a known-good version.
See ../SUPPORTED_TOOLBOX_TOOLS.md for all supported tool and auth types. For runnable SDK creation examples, see ../sample_toolboxes_crud.py.
This sample uses the Responses Protocol (azure-ai-agentserver-responses):
- OpenAI-compatible
/responsesendpoint on port8088 - Streaming SSE output
- Multi-turn conversation (history fetched automatically)
- 240-second per-request timeout
Check that TOOLBOX_ENDPOINT is set and the toolbox exists. The URL must include
?api-version=v1.
If a toolbox connection requires OAuth (e.g. GitHub), the agent logs:
OAuth consent required. Open the following URL in a browser to authorize...
Open the URL, complete the OAuth flow, then restart the agent. Until consent is granted,
the agent returns a oauth_consent_required tool message to callers.
handle_tool_error = True is set on all loaded tools, so MCP tool errors are returned
as tool messages rather than raising exceptions that would break conversation state.
The agent sanitizes malformed schemas from MCP servers (missing properties on
object-type schemas). If you see 400 Invalid tool schema errors, check the raw
tool schema returned by your MCP server.
The platform injects FOUNDRY_PROJECT_ENDPOINT. The code also accepts
AZURE_AI_PROJECT_ENDPOINT for backward compatibility, but always prefer the FOUNDRY_
variable in new deployments.
The azure-ai-agentserver-core[tracing] package is included in requirements.txt and
provides OpenTelemetry auto-instrumentation for LLM calls, MCP tool invocations, and
server spans. Traces can be exported to Azure Monitor (Application Insights).
Locally: set APPLICATIONINSIGHTS_CONNECTION_STRING in .env:
# Get the connection string from your Application Insights resource in the Azure Portal
# (Settings → Properties → Connection String)
APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey=<key>;IngestionEndpoint=...When deployed: the platform automatically injects APPLICATIONINSIGHTS_CONNECTION_STRING
from the Application Insights resource linked to your Foundry project. No additional
configuration is required.
Once APPLICATIONINSIGHTS_CONNECTION_STRING is set:
- Go to the Azure Portal and open your Application Insights resource.
- Navigate to Investigate → Transaction search to see individual traces.
- Use Investigate → Application map for an end-to-end dependency view.
Traces include LLM calls, tool invocations (including MCP calls to the toolbox), and
server spans. Each conversation turn produces a linked trace tree rooted at the
incoming /responses request.
kind: hosted # MUST be at root level
name: toolbox-langgraph-agent
protocols:
- protocol: responses
version: 1.0.0
environment_variables:
- name: AZURE_OPENAI_ENDPOINT
value: ${AZURE_OPENAI_ENDPOINT} # Single-brace syntax
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}WARNING: Do NOT use the nested
template:format —azd deploysilently ignores it.
Do NOT use${{VAR}}double-brace syntax — the container receives the literal string.
The toolbox is configured in azure.yaml (generated by azd ai agent init). You can add toolbox definitions under config.toolboxes in azure.yaml. See the azd README for supported toolbox scenarios.
# View container logs
azd ai agent monitor --tail 50See ../azd/KNOWN_ISSUES.md for all known issues with azd toolbox deployments.
main.py— agent entry point (env loading, agent name detection, telemetry, and LangGraph agent)../sample_toolboxes_crud.py— SDK samples for creating, listing, and deleting toolbox resources
This project welcomes contributions and suggestions.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.