This repo contains a deployable FastMCP server for Azure AI Search. It provisions Azure AI Search, Azure Blob Storage, Azure OpenAI embeddings, and an App Service-hosted MCP endpoint with azd, then seeds the search container from the local docs/ folder and starts the indexer.
- Ownership: Sole contributor across application code, identity, infrastructure, deployment automation, and validation.
- What it demonstrates: A production-oriented MCP and RAG pattern rather than a notebook-only retrieval demo.
- Security: Microsoft Entra bearer-token validation, managed identities, and role-based access to Search and Blob Storage.
- Validation: Deployed and tested end to end in Azure Government.
flowchart LR
Docs[Source documents] --> Blob[Azure Blob Storage]
Blob --> Indexer[AI Search indexer and skillset]
AOAI[Azure OpenAI embeddings] --> Indexer
Indexer --> Search[Azure AI Search hybrid and vector index]
Search --> MCP[FastMCP server on App Service]
Entra[Microsoft Entra ID] --> MCP
MCP --> Client[Authorized AI client or agent]
- Azure AI Search with a system-assigned managed identity.
- Azure Blob Storage with a private
aisearchdatacontainer for source documents. - Azure OpenAI with a
text-embedding-ada-002embeddings deployment. - An AI Search data source, vector index, skillset, and blob indexer using integrated vectorization.
- An App Service-hosted FastMCP server with managed identity access to Search and Blob Storage.
The Search pipeline follows the current Microsoft guidance for blob indexing and integrated vectorization: a blob data source, Text Split skill, Azure OpenAI Embedding skill, projected chunk index, Azure OpenAI vectorizer, semantic configuration, and an on-demand indexer run.
semantic_search runs hybrid semantic search with query-time vectorization. Results omit vector payloads and include retrievable fields such as chunk, title, source_path, and Search metadata.
get_image_from_content_path downloads image content from Blob Storage when a search result includes an explicit content_path field. The default Bicep index is text-first, so agents should only call this tool when that field is actually present in search results.
Install and sign in with the Azure Developer CLI, then run:
azd auth login
azd upDuring azd up, the postprovision hook runs:
uv run python scripts/seed_search.pyThat script loads azd outputs, uploads every non-hidden file under docs/ into the provisioned blob container, and starts the Azure AI Search indexer. The current sample content is docs/NDAA - 2027.pdf.
Because the storage account disables shared-key access, the signed-in Azure CLI user must have data-plane upload permission on the storage account, such as Storage Blob Data Contributor. The Search indexer itself reads blobs through the Search service managed identity, which the Bicep deployment grants Storage Blob Data Reader.
Set azd environment values before azd up when you want to override defaults:
azd env set AZURE_LOCATION eastus
azd env set SEARCH_SERVICE_SKU basic
azd env set STORAGE_ACCOUNT_SKU Standard_LRS
azd env set CLOUD_NAME AzureCloudFor Azure Government, set:
azd env set CLOUD_NAME AzureUSGovernmentAfter deployment, azd writes outputs such as SEARCH_SERVICE_ENDPOINT, SEARCH_INDEX_NAME, SEARCH_INDEXER_NAME, STORAGE_ACCOUNT_BLOB_ENDPOINT, and STORAGE_ACCOUNT_CONTAINER_NAME to the environment. The MCP server reads those values automatically in Azure App Service and from .azure/<env>/.env during local development.
Use uv for local Python operations:
uv sync
uv run python main.pyThe server listens on http://localhost:8000 using FastMCP streamable HTTP transport.
To re-upload docs/ and run the indexer after changing source files:
uv run python scripts/seed_search.pyThe MCP server supports optional bearer-token validation:
- Microsoft Entra ID JWKS validation when
AZURE_AD_REQUIRE_AUTH=true. - Symmetric HS256 JWT validation when
MCP_AUTH_SECRETis set. - No MCP-layer auth when neither is configured, which is suitable only for local development.
For Entra ID auth, configure:
AZURE_AD_REQUIRE_AUTH=true
AZURE_AD_TENANT_ID=<tenant-id>
AZURE_AD_CLIENT_ID=<mcp-app-client-id>Requests without a valid Authorization: Bearer <token> header receive HTTP 401 when auth is enabled.
- The blob indexer is configured for
contentAndMetadata, explicit source attribution throughsource_path, and tolerant handling of individual unsupported or unprocessable files. - Integrated vectorization uses the same embedding model for indexing and query-time vectorization, as recommended by Azure AI Search docs.
- Indexer execution is on demand after docs upload. If an indexer run is already in progress, the seeding script logs the condition and leaves the active run alone.