Storage Intelligence MCP/A2A Agent
Production-like, read-only Azure storage intelligence pilot with a 2,500-accountsynthetic estate spanning 339 subscriptions across Dev, QA, Perf, and Prod, deterministicanalytics, private Foundry tools, and an Entra-protected web application.
The same deterministic agent is available through REST, an official MCPStreamable HTTP server, and A2A v1 JSON-RPC/HTTP+JSON endpoints. SeeMCP and A2A integration for client configuration,authentication, discovery, and request examples.
Product experience
- PepsiCo-branded responsive dashboard with pinned, locally served React assets.
- Persistent English/Spanish language switch in the top-right header for globallydistributed teams in Hyderabad, Barcelona, Mexico, the US, and the UK. Navigation,forms, statuses, accessibility labels, dynamic counts, risk factors, built-in questions,and deterministic answer summaries render in the selected language without changingAPI identifiers or resource names.
- Manual pilot onboarding by storage account name, tenant ID, management group,subscription, environment, subsidiary/business unit, region, and access tier.
- Authenticated selection-list management for adding tenants, management groups,subscriptions, subsidiaries/business units,plus the complete customer-facing Azure public-region catalog in every region selector.
- Bulk XLSX/CSV onboarding for avoiding repetitive manual entry. Imports are validatedatomically, reject duplicates, and update only the in-memory pilot inventory.
- Administrator-only tenant discovery that runs read-only Azure CLI commands across allauthorized subscriptions and imports tenant, management-group, subsidiary/business-unit,environment, storage account, region, tier, SKU, access/network posture, andproject-governance tags.
- Tiny Databricks, Fabric Lakehouse, SAP, Azure Data Factory, SFTP, and ApplicationInsights badges on linked storage accounts. The synthetic estate deterministicallyrandomizes these relationships; discovery reads native
isSftpEnabled/isHnsEnabledproperties plusApplicationInsights/AppInsightstag aliases. - Deterministic capacity, cost, risk, Databricks, forecast, anomaly, tier-savings,evidence, confidence, and freshness investigations.
- Risk concentration lists Growth, Cost, Freshness, Operations, Databricks, Configuration,Security, and Governance categories with a calm low-saturation palette. Securityexplicitly scores SAS/shared keys, public access, missing private endpoints, NSG/ASGlinks, and missing service-principal access. Governance uses project, business-unit,last-accessed, and defunct tags. A donut-style pie chart summarizes thedominant-risk distribution, while every scoped account scoring at least 20 remains inthe ranked, vertically scrollable list. Hovering a pie segment displays the riskdescription, account count, and percentage; keyboard focus shows the largest segment.
- Actionable Data Health posture tiles: Stale accounts, Missing lifecycle,SAS Key, Public Access, No Private Endpoint,No Service Principal, No GRS/GZRS, NSG/ASG linked, and Defunct Projectsplus SFTP Enabled and AppInsights Data are buttons. Selecting one immediatelyloads every matching account for the active scope into a risk-sorted, verticallyscrollable panel directly below the tiles on the Data Health page. Overview remainsfocused on estate capacity, cost, savings, risk concentration, and onboarding. Theformer standalone stale-account details panel is removed because Stale accounts now usesthis common drilldown.
- Priority findings explains the Growth and Operations component scores. Operations isthe 0โ100 throttling/latency subscore; the right-side value is the overall weightedaccount risk score out of 100.
Manual and spreadsheet onboarding never create or change Azure Storage resources.
The Container Apps web workload uses one always-ready Consumption replica with1 vCPU and 2 GiB memory. This keeps A2A task lookup and cancellation consistent withthe SDK's process-local task handler. Ingress targets port 8000, matching Uvicorn andthe Dockerfile, and probes allow 10 seconds for transient load. Private Function deploymentand Foundry smoke tests are intentionally decoupled from web startup so the publicEntra-protected UI cannot be blocked by a private dependency. Application version0.1.0 remains unchanged.
Functional views
- Agent Investigation runs scoped deterministic tools, displays the full trustenvelope and structured result, explains why every returned account was flagged, keepsevidence citations aligned with all unique returned accounts, offers a broad reusablecatalog of operational/financial/platform questions, saves new authenticated questionsfor future sessions, and retains the latest eight investigations in-session.
- Savings Simulator models 1-100% tiering adoption, compares 10/25/50% baselines,ranks the top 20 candidates, and retains retrieval/retention caveats.
- Findings combines risk, robust growth anomalies, data freshness, and savings actionsinto a severity-sorted inbox. Total Findings, Data Freshness, Growth Anomaly,Risk, and Savings Action are clickable summary tiles; selecting one immediatelyfilters the scrollable results panel below. The former duplicate filter-button row isremoved.
- Data Health shows freshness coverage, connector/source status, lifecycle and assumedtier gaps, and a scrollable stale-account remediation list. For administrators, thevisible Disabled status is a button: clicking it enables that connector, changes thestatus to Enabled, and reveals a clickable Run action. A completed pilot-fixturerun changes the status to Healthy and shows synced/eligible counts and last-run time.Security posture cards expose SAS/shared keys, public access, missing private endpoints,missing service-principal access, non-GRS/GZRS replication, NSG/ASG links, defunctprojects, missing last-access tags, SFTP-enabled endpoints, and ApplicationInsights-linked storage.
- Data Health places Synthetic pilot, Azure CLI discovery, Azure Resource Graph,Blob Inventory, Azure Monitor Metrics, Cost Management exports, andDatabricks system tables immediately after the global filters/reset row.
Tenant-wide admin discovery
Administrators see a dedicated Admin item in the left navigation. ItsPull Tenant Wide Storage Account Details action uses Azure CLI argument arrays (nevera shell command string) to enumerate every enabled subscription visible to theauthenticated identity and run az storage account list for each subscription. Resultsare ingested idempotently into the pilot inventory and upserted into the private Cosmos DBstorage-intelligence/storage-accounts container.
Configure the runtime with:
| Variable | Purpose | Default |
|---|---|---|
ADMIN_ROLE |
Entra app role required by admin endpoints | StorageIntelligence.Admin |
DISCOVERY_TENANT_IDS |
Optional comma-separated tenant IDs; empty means every tenant visible in the CLI account cache | empty |
DISCOVERY_USE_MANAGED_IDENTITY |
Run az login --identity with AZURE_CLIENT_ID |
true |
DISCOVERY_CRON |
Initial five-field discovery schedule | 0 */6 * * * |
DISCOVERY_SCHEDULE_PATH |
Persisted admin schedule configuration | data/discovery-schedule.json |
DISCOVERY_OUTPUT_PATH |
Scheduled CLI snapshot path | data/discovered-storage-accounts.json |
AZURE_CLI_PATH |
Azure CLI executable | az |
COSMOS_INVENTORY_ENABLED |
Persist manual and scheduled discovery results to Cosmos DB | false locally; true in Azure |
COSMOS_ENDPOINT |
Private Cosmos DB account endpoint | required when persistence is enabled |
COSMOS_DATABASE |
Inventory database name | storage-intelligence |
COSMOS_CONTAINER |
Storage-account container name | storage-accounts |
SAVED_QUESTIONS_PATH |
Atomic localhost question-library file when Cosmos is disabled | data/saved-agent-questions.json |
The managed identity or automation principal must be granted read-only access in everytarget subscription/tenant. This project deliberately does not assign tenant-wideReader roles. Cross-tenant discovery works only after the identity is explicitlyauthorized in each tenant.
Run discovery directly:
.\scripts\run-storage-discovery.ps1
Administrators can edit the five-field cron expression directly in the dashboard. Theschedule is validated with croniter, persisted atomically, and used by the in-processscheduler after restart. The next execution time and common UTC cron examples are shownin the role-gated Admin view. Provisioning creates the StorageIntelligence.Admin Entraapp role and assigns it to the deploying user. Each completed pull reports the number ofCosmos DB upserts. Cosmos uses the web app's managed identity, a database-scoped built-inData Contributor assignment, /subscription_id partitioning, and no account keys.
For an external automation host, install the supplied six-hour fallback cron:
crontab config/storage-discovery.cron
The external scheduled command writes an atomic JSON snapshot. The in-app schedulerupserts the same account details to Cosmos DB. Neither path requests storage keys ormutates estate resources.
Discovery recognizes Databricks, Fabric Lakehouse, SAP, Azure Data Factory, andApplication Insights tag aliases plus native SFTP/HNS state.It also reads Project/ProjectName, BusinessUnit, LastAccessedDate,ProjectStatus/ProjectDefunct, UsesSASKeys, ServicePrincipalAccess,NetworkSecurityGroup/NSG, and ApplicationSecurityGroup/ASG. Azure resourceproperties supply shared-key access, public network/blob access, private endpoint state,and replication SKU. Linked accounts appear in a dedicated dashboard section with compactaccessible badges.
The navigation footer displays ยฉ 2026 PepsiCo. All rights reserved. followed by tiny,accessible Microsoft, Azure, and the supplied Azure AI Foundry image mark. The Foundry PNGis committed under src/web/static/assets with a SHA-256 manifest.
Spreadsheet format
Upload an .xlsx workbook or UTF-8 .csv file with a header row and these columns:
| Column | Example |
|---|---|
name |
stfinancearchive01 |
tenant_id |
11111111-1111-4111-8111-111111111111 |
management_group |
mg-americas-platform |
subscription |
platform-prod |
environment |
Prod |
subsidiary |
PepsiCo Beverages North America |
region |
eastus2 |
tier |
Cool |
The importer accepts up to 10,000 rows or 5 MB per file. Friendly header aliases suchas storage_account_name, tenant, managementgroup, subscription_name,environment/stage/env, Business unit, azure_region, and access_tier arenormalized automatically.business_unit is a compatibility alias for subsidiary. Every hierarchy value mustexist in the pilot catalog; known synthetic subscriptions are validated against theirtenant, management group, environment, and subsidiary. Regions may use any code from the completeAzure public-region selector; tiers must use an available access tier.
The versioned synthetic catalog contains exactly 339 subscriptions. Each subscription hasa deterministic UUID, tenant, management group, subsidiary, and one of Dev, QA,Perf, or Prod. All 339 names appear in the global subscription selector.
Investigation question library
GET /api/questions returns the built-in and saved question catalog.POST /api/questions accepts a new 3-500 character question, normalizes whitespace,rejects case-insensitive duplicates, and caps the shared library at 100 custom questions.Azure stores custom questions as saved-agent-question documents in the existing privateCosmos container under the __agent_questions__ partition. Localhost uses the atomic JSONpath above. Saving a question does not execute it or mutate an Azure resource.
Local run
Python 3.13 is required. Node.js and npm are not used.
python -m venv .venv
.\.venv\Scripts\python -m pip install -e ".[test]"
$env:AUTH_DISABLED = "true"
.\.venv\Scripts\python -m uvicorn web.app:app --host 127.0.0.1 --port 8000
Open http://127.0.0.1:8000. Run acceptance tests with:
.\.venv\Scripts\python -m pytest
The language preference is stored in browser localStorage understorage-intelligence-language. English (en) is the default; Spanish (es) updates thedocument language and title. Built-in Spanish questions are canonicalized back to theirEnglish deterministic intent before API submission, while the backend also recognizescommon Spanish intent phrases for newly authored questions.
Architecture
src/storage_intelligence: synthetic generator, connectors, analytics, query router.src/protocols/service.py: protocol-neutral read-only agent facade.src/protocols/mcp_server.py: MCP tools, resource, prompt, HTTP mount, and stdio entry point.src/protocols/a2a_server.py: A2A Agent Card, JSON-RPC/REST routes, task executor, and artifacts.src/web: FastAPI and vendored React 18.3.1 browser UI.src/function_app.py: private OpenAPI tools and durable fan-out/fan-in collection.src/agent: Foundry instructions, OpenAPI contract, deploy/invoke scripts, and evals.infra/foundry: official template 19 baseline and unmodified supporting modules.infra/functions-base: preserved official Flex Consumption base modules.infra: composed workload Bicep and AZD parameters.
See product specification,architecture, andprotocol integration.
Azure workflow
The approved .azure/deployment-plan.md is the source of truth. Deployment uses:
azd env new storage-intel-pilot
azd env set AZURE_LOCATION swedencentral
azd env set AZURE_SUBSCRIPTION_ID c82406dd-f84c-42df-9586-c6f02abda6df
azd provision --preview --no-prompt
azd provision --no-prompt
azd deploy --no-prompt
The deployment scripts create or reuse secretless Entra application registrations,enable ID-token issuance for Container Apps Easy Auth, deploy the web image and Functionspackage, then create the Foundry prompt-agent version. Easy Auth accepts both theapplication client ID and its api:// identifier URI as token audiences.Production connectors remain disabled unless their explicit flags and least-privilegeroles are configured.
Cost caveats
Private Foundry Standard requires fixed-cost AI Search Standard and Premium ACR. Cosmos DB,monitoring ingestion, model tokens, private endpoints, and Container Apps add usage-basedcosts. The pilot avoids estate API and Databricks query charges by using synthetic data.