Skip to content

Add MCP server with Entra ID auth and update documentation for msdocs-fastapi-postgresql-sample-app#19

Open
yogitasrivastava wants to merge 3 commits intoAzure-Samples:mainfrom
yogitasrivastava:main
Open

Add MCP server with Entra ID auth and update documentation for msdocs-fastapi-postgresql-sample-app#19
yogitasrivastava wants to merge 3 commits intoAzure-Samples:mainfrom
yogitasrivastava:main

Conversation

@yogitasrivastava
Copy link

This pull request introduces major enhancements to the FastAPI restaurant review application by integrating a Model Context Protocol (MCP) server, enabling Azure AI Foundry agent access via Microsoft Entra ID authentication, and updating the infrastructure to support these features. It also improves documentation with a comprehensive setup and deployment guide.

Key changes include:

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 sample app needs to demonstrate how to secure an MCP endpoint for agent identity access to reduce the risk of agentic threats. 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://<client-id>/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

- Add mcp_server.py with 4 MCP tools (list/get/create restaurants & reviews)
- Mount MCP server at /mcp in app.py with lifespan support
- Add mcp[cli] dependency to pyproject.toml
- Set gunicorn worker lifespan to 'on' for MCP session manager
- Add comprehensive auth guide (GUIDE_AUTH_MCP_SERVER.md)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant