Azure-Samples / Azure-Samples/msdocs-fastapi-postgresql-sample-app

Enable Agent Identity Auth for Foundry Agents for sample msdocs-fastapi-postgresql-sample-app

Ouverte
#17 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
Bicep
Étoiles
11
Forks
60
Merge moyen
1 j 18 h
PR mergées (30 j)
2

Description

## Summary

Add a Model Context Protocol (MCP) server to the existing FastAPI restaurant reviews sample app, secure it with Microsoft Entra ID authentication (EasyAuth v2), and preauthorize Azure AI Foundry agent identities to call the MCP tools using managed identity (`ServiceIdentity`) authentication via the `client_credentials` flow.

## Motivation

Azure AI Foundry agents need to consume MCP servers hosted on Azure App Service. The existing samples needs to demonstrate how to secure an MCP endpoint for agent identity access to ensure agentic securty risks are minimized. This change provides a working, end-to-end example that developers can follow to:

1. Add an MCP server to an existing FastAPI app
2. Secure it with Entra ID authentication
3. Preauthorize Foundry agent identities (which use `ServiceIdentity` type principals, not standard app registrations)

## Changes

### New Files
- **`src/fastapi_app/mcp_server.py`** — MCP server with 4 tools (`list_restaurants_mcp`, `get_details_mcp`, `create_review_mcp`, `create_restaurant_mcp`) using `FastMCP` with `stateless_http=True`
- **`GUIDE_AUTH_MCP_SERVER.md`** — Comprehensive step-by-step guide covering app registration, EasyAuth configuration, PRM setup, Foundry agent preauthorization, verification, troubleshooting, and 22 test cases

### Modified Files
- **`src/pyproject.toml`** — Added `mcp[cli]` to dependencies
- **`src/fastapi_app/app.py`** — Imported and mounted MCP server at `/mcp`, added `mcp_lifespan` context manager to FastAPI app
- **`src/my_uvicorn_worker.py`** — Changed `lifespan` from `"auto"` to `"on"` (required for MCP session manager to start under gunicorn)
- **`README.md`** — Updated title, description, and added sections for MCP tools, architecture diagram, local MCP verification, Entra ID auth setup steps, Foundry agent integration, and key learnings
- **`infra/main.bicep`**, **`infra/resources.bicep`** — Infrastructure updates from `azd up` deployment

## Technical Details

### MCP Server
- Mounted at `/mcp/mcp` under the existing FastAPI app
- Uses `stateless_http=True` for compatibility with FastAPI mount
- `mcp_lifespan` context manager ensures the MCP session manager starts/stops with the app
- Tools use `asyncio.to_thread()` to run synchronous SQLModel/SQLAlchemy DB queries

### Authentication Architecture
Azure AI Foundry Agent

│ client_credentials flow → token with MCP.Access role

Azure App Service (EasyAuth ~2, Return401)

│ JWT validated: issuer, audience, allowedClientApplications

FastAPI + gunicorn (lifespan: on)

│ /mcp/mcp → FastMCP (stateless_http)

MCP Tools → PostgreSQL

### Key Configuration

| Component | Setting | Value |
|-----------|---------|-------|
| EasyAuth | `runtimeVersion` | `~2` (v1 doesn't enforce auth properly) |
| EasyAuth | `unauthenticatedClientAction` | `Return401` |
| App Role | `MCP.Access` | `allowedMemberTypes: ["Application"]` |
| PRM | `WEBSITE_AUTH_PRM_DEFAULT_WITH_SCOPES` | `api:///user_impersonation` |
| Gunicorn | `lifespan` | `"on"` (critical for MCP session manager) |

### Key Learnings Documented
- **`ServiceIdentity` principals** (Foundry agents) cannot be added to `preAuthorizedApplications` — use app role assignments + `allowedClientApplications` instead
- A **service principal must be created** for the app registration before role assignments work (commonly missed step)
- **`runtimeVersion: "~2"`** is required for EasyAuth to properly enforce authentication
- The **PRM endpoint** (`/.well-known/oauth-protected-resource`) is served by EasyAuth and is exempt from authentication by design

## Test Coverage

22 test cases across 3 groups:
- **Group A (8 tests):** MCP functionality without authentication (auth disabled)
- **Group B (11 tests):** Authentication enforcement — unauthenticated, fake token, wrong audience, valid token flows
- **Group C (3 tests):** Python MCP client programmatic tests (with/without auth)

## Verification

- Foundry agent (`mslearnagent`) successfully connects and enumerates all 4 MCP tools (`mcp_list_tools` status: `OK`)
- Entra ID sign-in logs show successful `ServiceIdentity` authentication
- PRM endpoint serves correct OAuth metadata
- Unauthenticated requests correctly return 401

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

Lisez les points d’entrée FastAPI existants dans src/fastapi_app/app.py et src/my_uvicorn_worker.py, puis examinez les modifications indiquées pour src/fastapi_app/mcp_server.py, src/pyproject.toml et les fichiers d’infrastructure. Utilisez GUIDE_AUTH_MCP_SERVER.md pour exécuter les 22 cas de test et étapes de vérification documentés. La tâche est terminée lorsque les quatre outils MCP fonctionnent, que l’authentification renvoie 401 lorsqu’elle est requise, que les métadonnées OAuth sont disponibles et que l’agent Foundry signale mcp_list_tools comme OK.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
azure, fastapi, postgresql, python
Domaine
api, authentication, backend, cloud, databases, documentation
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
Clairement spécifiée
Accessibilité débutants
35/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.