{"id":50558477,"url":"https://github.com/jonahandersson/msbuild2026-code2agents-jonahandersson-demo","last_synced_at":"2026-06-04T09:30:49.011Z","repository":{"id":362334225,"uuid":"1241721485","full_name":"jonahandersson/msbuild2026-code2agents-jonahandersson-demo","owner":"jonahandersson","description":"This the code repo of Jonah Andersson for Microsoft Build 2026 session ","archived":false,"fork":false,"pushed_at":"2026-06-02T18:37:30.000Z","size":38525,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-03T19:11:34.558Z","etag":null,"topics":["azure","azure-functions","bicep"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonahandersson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-17T18:27:40.000Z","updated_at":"2026-06-03T14:51:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jonahandersson/msbuild2026-code2agents-jonahandersson-demo","commit_stats":null,"previous_names":["jonahandersson/msbuild2026-code2agents-jonahandersson-demo"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/jonahandersson/msbuild2026-code2agents-jonahandersson-demo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonahandersson%2Fmsbuild2026-code2agents-jonahandersson-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonahandersson%2Fmsbuild2026-code2agents-jonahandersson-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonahandersson%2Fmsbuild2026-code2agents-jonahandersson-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonahandersson%2Fmsbuild2026-code2agents-jonahandersson-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonahandersson","download_url":"https://codeload.github.com/jonahandersson/msbuild2026-code2agents-jonahandersson-demo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonahandersson%2Fmsbuild2026-code2agents-jonahandersson-demo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33899697,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-04T02:00:06.755Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure","azure-functions","bicep"],"created_at":"2026-06-04T09:30:47.900Z","updated_at":"2026-06-04T09:30:49.003Z","avatar_url":"https://github.com/jonahandersson.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# From Code to Agents: Build Production MCP Servers on Azure Functions\n\n\u003e Stack: C# / .NET 10 · Azure Functions (isolated worker) · MCP Extension · Microsoft Agent Framework 1.0 · Microsoft Foundry · Azure DevOps\n\nProduction-grade reference for hosting a **Model Context Protocol (MCP) server** on Azure\nFunctions and driving it from an agent built with the **Microsoft Agent Framework** on\n**Microsoft Foundry**. Goes end-to-end from `[McpToolTrigger]` attribute on a Function\nto an agent that diagnoses a failed deployment and opens a rollback PR in Azure DevOps —\nusing the same patterns you'd ship in production.\n\n---\n\n## Why MCP on Azure Functions\n\nAgents need a standard way to discover and invoke tools at runtime.\n**MCP (Model Context Protocol)** is that standard. Azure Functions, with the\n**MCP Extension** (GA at Ignite 2025), is a strong host for production MCP servers:\n\n- Scale to zero, scale to thousands.\n- Entra-backed auth at the `/runtime/webhooks/mcp` endpoint.\n- Existing CI/CD and observability stories already work.\n- Managed Identity end-to-end — no PATs, no connection strings in code.\n\n---\n\n## What it does\n\nThe sample scenario: a deployment of `shop-api` to `main` is failing. The DevOps agent:\n\n1. Lists the most recent deployments for the repo and branch.\n2. Diagnoses the latest failed deployment.\n3. Identifies the last known-good commit.\n4. **Creates a rollback PR in Azure DevOps**, with the agent's reasoning in the description.\n\nThe MCP server (this repo's Function app) exposes three tools:\n\n| Tool name                  | What it does                                                  |\n|----------------------------|---------------------------------------------------------------|\n| `get_recent_deployments`   | Lists recent builds for a repo + branch                       |\n| `diagnose_deployment`      | Returns likely root cause + the last known-good commit        |\n| `create_rollback_pr`       | Creates a PR rolling back to a target commit, with a reason   |\n\n---\n\n## Prerequisites\n\n| Thing                  | Version / notes                                              |\n|------------------------|--------------------------------------------------------------|\n| .NET SDK               | **10.0** (preview). Falls back to 9.0 — see \"Fallback\" below.|\n| Azure Functions Core Tools | v4.x                                                    |\n| Azure CLI              | 2.60+                                                        |\n| Azure subscription     | Contributor on a resource group                              |\n| Microsoft Foundry project | With a model deployment (e.g. `gpt-5.4-mini` or `gpt-4o-mini`) |\n| Azure DevOps org       | With a project, a repo, and at least one build pipeline      |\n| GitHub                 | For repo + Actions (OIDC federated to Azure)                 |\n\n\u003e **Devcontainer is recommended.** Open this repo in a GitHub Codespace and everything\n\u003e above is pre-installed except the cloud accounts.\n\n---\n\n## Quick start (local, no cloud needed)\n\nThe MCP server has a `FakeDeploymentService` so you can run the whole flow against\nin-memory data — useful for local development without Azure DevOps access.\n\n**Option A — .NET Aspire (recommended for local dev):**\n\n```bash\ndotnet user-secrets --project src/AppHost set \"Parameters:foundry-endpoint\" \\\n  \"https://\u003cyour-foundry\u003e.services.ai.azure.com/api/projects/\u003cproject\u003e\"\n\ndotnet run --project src/AppHost\n```\n\nOpens the Aspire dashboard at \u003chttps://localhost:17081\u003e with the MCP server,\nthe agent, and live traces/logs/metrics flowing through both.\n\n**Option B — Manual (two terminals, no Aspire):**\n\n```bash\n# Terminal 1 — MCP server\ncd src/DeploymentMcp\ncp local.settings.sample.json local.settings.json\nfunc start\n\n# Terminal 2 — Agent\ncd src/DevOpsAgent\nexport FOUNDRY_PROJECT_ENDPOINT=\"https://\u003cyour-foundry\u003e.services.ai.azure.com/api/projects/\u003cproject\u003e\"\nexport FOUNDRY_MODEL=\"gpt-4o-mini\"\nexport MCP_SERVER_URL=\"http://localhost:7071/runtime/webhooks/mcp\"\ndotnet run\n```\n\nTry the prompt: *\"The latest deployment of shop-api to main is failing. Investigate and roll back if needed.\"*\n\n---\n\n## Connecting to a real Azure DevOps project\n\nIf you don't have an Azure DevOps project yet, follow\n**[demo/shop-api-seed/SETUP-AZDO.md](./demo/shop-api-seed/SETUP-AZDO.md)** —\nthe full walkthrough that gets you from \"no AzDO\" to \"agent creates real rollback PRs.\"\n\nShort version once you have an org + project + repo:\n\n1. Set `DemoMode = false` in `local.settings.json` (or in App Settings on Azure).\n2. Configure `AzureDevOps:OrgUrl` and `AzureDevOps:Project`.\n3. Add the Function App's Managed Identity as a user in Azure DevOps with\n   Project Contributors permissions (see Step 5 of SETUP-AZDO.md).\n\n---\n\n## Deploying to Azure\n\n```bash\nazd auth login\nazd up\n```\n\n`infra/main.bicep` provisions:\n\n- Function App on **Flex Consumption** plan\n- User-assigned Managed Identity\n- Storage account (for the Function runtime)\n- Application Insights + Log Analytics workspace\n- Role assignment so the Function can read your Foundry project\n\nThe Azure DevOps role assignment is a manual step because it spans services. See\n[demo/shop-api-seed/SETUP-AZDO.md](./demo/shop-api-seed/SETUP-AZDO.md) for the\nrequired AzDO scopes on the Function App's Managed Identity.\n\n### Deploying from GitHub Actions (OIDC federation)\n\nThe [.github/workflows/deploy.yml](./.github/workflows/deploy.yml) workflow runs\n`azd up` on every push to `main`. It authenticates to Azure with **OpenID\nConnect federation** — no client secrets stored in GitHub, no PATs.\n\n**One-time setup:**\n\n1. **Create an Entra app registration with a federated credential.**\n   The fastest path is `azd pipeline config` from a local clone:\n\n   ```bash\n   azd auth login\n   azd pipeline config --provider github\n   ```\n\n   This creates the app registration, sets up federated credentials for the\n   `main` branch + pull requests, grants `Contributor` + `User Access\n   Administrator` on the target subscription, and writes the GitHub secrets\n   below for you. If you prefer to do it by hand, the equivalent `az` flow is\n   in the [azd docs](https://learn.microsoft.com/azure/developer/azure-developer-cli/configure-devops-pipeline).\n\n2. **Confirm the GitHub secrets and variables exist** under\n   *Settings → Secrets and variables → Actions*:\n\n   | Scope    | Name                     | Example                                |\n   |----------|--------------------------|----------------------------------------|\n   | Secret   | `AZURE_CLIENT_ID`        | GUID of the app registration           |\n   | Secret   | `AZURE_TENANT_ID`        | Your Entra tenant GUID                 |\n   | Secret   | `AZURE_SUBSCRIPTION_ID`  | Target subscription GUID               |\n   | Variable | `AZURE_ENV_NAME`         | `demo`                                 |\n   | Variable | `AZURE_LOCATION`         | `swedencentral`                        |\n   | Variable | `AZURE_NAME_PREFIX`      | `mcpdemo` (3–11 lowercase chars)       |\n\n3. **Verify the federated credential subject** matches the workflow trigger.\n   For pushes to `main`, the subject should be\n   `repo:\u003cowner\u003e/\u003crepo\u003e:ref:refs/heads/main`. Mismatch is the #1 cause of\n   `AADSTS70021` errors in the `azure/login` step.\n\nNo Azure DevOps PAT is ever stored — the Function App's *runtime* identity\n(a user-assigned Managed Identity provisioned by Bicep) authenticates to\nAzure DevOps separately. See [SETUP-AZDO.md](./demo/shop-api-seed/SETUP-AZDO.md)\nfor the required AzDO scopes on that identity.\n\n---\n\n## Repo walkthrough\n\n```\nbuild2026-mcp-azure-functions/\n├── .devcontainer/         Codespace config (one-click dev env)\n├── .github/workflows/     CI + OIDC-federated deploy\n├── infra/                 Bicep IaC (azd-ready)\n├── src/\n│   ├── AppHost/           .NET Aspire orchestrator (local one-command startup)\n│   ├── ServiceDefaults/   Shared OTel + App Insights + service discovery\n│   ├── DeploymentMcp/     Azure Function = MCP server (the headliner)\n│   └── DevOpsAgent/       Console app = MCP client (Microsoft Agent Framework)\n├── demo/\n│   ├── shop-api-seed/     Azure DevOps target repo + setup script\n│   ├── observability/     KQL queries for the App Insights views\n│   └── cached-responses/  Optional canned payloads for offline runs\n├── azure.yaml             azd entry point\n├── Directory.Packages.props  Central package management\n└── global.json            Pins SDK version\n```\n\n---\n\n## Verifying the SDK surface\n\nThe MCP Extension for Functions and Microsoft Agent Framework 1.0 are evolving fast.\nWhen upgrading, verify two things against the latest samples:\n\n1. **The `[McpToolTrigger]` and `[McpToolProperty]` attribute signatures** in\n   `Microsoft.Azure.Functions.Worker.Extensions.Mcp`.\n   Sample: \u003chttps://github.com/Azure-Samples/remote-mcp-functions-dotnet\u003e\n\n2. **The Agent Framework MCP client class name and constructor** in\n   `Microsoft.Agents.AI` / `Microsoft.Agents.AI.Mcp`.\n   Sample: \u003chttps://github.com/microsoft/agent-framework\u003e\n\nThe code in this repo follows the documented public API at time of writing. If a name\nshifted between versions, the fix is usually a one-line rename.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonahandersson%2Fmsbuild2026-code2agents-jonahandersson-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonahandersson%2Fmsbuild2026-code2agents-jonahandersson-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonahandersson%2Fmsbuild2026-code2agents-jonahandersson-demo/lists"}