@@ -48,15 +48,31 @@ environmentName = "Default-<envGuid>" (everything before first ".")
4848flowName = "<flowGuid>" (everything after first ".")
4949```
5050
51- Also: skip entries from ` list_store_flows ` that have no ` displayName ` —
52- these are sparse/orphaned records.
51+ Also: skip entries that have no ` displayName ` or have ` state=Deleted ` —
52+ these are sparse records or flows that no longer exist in Power Automate.
53+ If a deleted flow has ` monitor=true ` , suggest disabling monitoring
54+ (` update_store_flow ` with ` monitor=false ` ) to free up a monitoring slot
55+ (standard plan includes 20).
5356
5457---
5558
5659## The Write Tool: ` update_store_flow `
5760
58- ` update_store_flow ` is the only tool that writes governance metadata. It uses
59- merge semantics — only fields you provide are updated. Returns the full
61+ ` update_store_flow ` writes governance metadata to the ** Flow Studio cache
62+ only** — it does NOT modify the flow in Power Automate. These fields are
63+ not visible via ` get_live_flow ` or the PA portal. They exist only in the
64+ Flow Studio store and are used by Flow Studio's scanning pipeline and
65+ notification rules.
66+
67+ This means:
68+ - ` ownerTeam ` / ` supportEmail ` — sets who Flow Studio considers the
69+ governance contact. Does NOT change the actual PA flow owner.
70+ - ` rule_notify_email ` — sets who receives Flow Studio failure/missing-run
71+ notifications. Does NOT change Microsoft's built-in flow failure alerts.
72+ - ` monitor ` / ` critical ` / ` businessImpact ` — Flow Studio classification
73+ only. Power Automate has no equivalent fields.
74+
75+ Merge semantics — only fields you provide are updated. Returns the full
6076updated record (same shape as ` get_store_flow ` ).
6177
6278Required parameters: ` environmentName ` , ` flowName ` . All other fields optional.
@@ -100,7 +116,7 @@ the CoE Starter Kit's Developer Compliance Center.
1001161. Ask the user which compliance fields they require
101117 (or use their organization's existing governance policy)
1021182. list_store_flows
103- 3. For each flow (skip entries without displayName):
119+ 3. For each flow (skip entries without displayName or state=Deleted ):
104120 - Split id → environmentName, flowName
105121 - get_store_flow(environmentName, flowName)
106122 - Check which required fields are missing or empty
@@ -127,6 +143,10 @@ the CoE Starter Kit's Developer Compliance Center.
127143> suggestions based on common Power Platform governance patterns (CoE Starter
128144> Kit). Ask the user what their requirements are before flagging flows as
129145> non-compliant.
146+ >
147+ > ** Tip:** Flows created or updated via MCP already have ` description `
148+ > (auto-appended by ` update_live_flow ` ). Flows created manually in the
149+ > Power Automate portal are the ones most likely missing governance metadata.
130150
131151### 2. Orphaned Resource Detection
132152
@@ -137,7 +157,7 @@ Find flows owned by deleted or disabled Azure AD accounts.
1371572. Filter where deleted=true AND ownerFlowCount > 0
138158 Note: deleted makers have NO displayName/mail — record their id (AAD OID)
1391593. list_store_flows → collect all flows
140- 4. For each flow (skip entries without displayName):
160+ 4. For each flow (skip entries without displayName or state=Deleted ):
141161 - Split id → environmentName, flowName
142162 - get_store_flow(environmentName, flowName)
143163 - Parse owners: json.loads(record["owners"])
@@ -153,6 +173,14 @@ Find flows owned by deleted or disabled Azure AD accounts.
153173> ` update_store_flow ` updates governance metadata in the cache only. To
154174> transfer actual PA ownership, an admin must use the Power Platform admin
155175> center or PowerShell.
176+ >
177+ > ** Note:** Many orphaned flows are system-generated (created by
178+ > ` DataverseSystemUser ` accounts for SLA monitoring, knowledge articles,
179+ > etc.). These were never built by a person — consider tagging them
180+ > rather than reassigning.
181+ >
182+ > ** Coverage:** This workflow searches the cached store only, not the
183+ > live PA API. Flows created after the last scan won't appear.
156184
157185### 3. Archive Score Calculation
158186
@@ -161,7 +189,7 @@ candidates. Aligns with the CoE Starter Kit's archive scoring.
161189
162190```
1631911. list_store_flows
164- 2. For each flow (skip entries without displayName):
192+ 2. For each flow (skip entries without displayName or state=Deleted ):
165193 - Split id → environmentName, flowName
166194 - get_store_flow(environmentName, flowName)
1671953. Compute archive score (0-7), add 1 point for each:
@@ -185,14 +213,21 @@ candidates. Aligns with the CoE Starter Kit's archive scoring.
185213 update_store_flow(environmentName, flowName, tags="<existing> #archived")
186214```
187215
216+ > ** What "archive" means:** Power Automate has no native archive feature.
217+ > Archiving via MCP means: (1) stop the flow so it can't run, and
218+ > (2) tag it ` #archived ` so it's discoverable for future cleanup.
219+ > Actual deletion requires the Power Automate portal or admin PowerShell
220+ > — it cannot be done via MCP tools.
221+
188222### 4. Connector Audit
189223
190- Audit which connectors are in use across the tenant . Useful for DLP impact
191- analysis and premium license planning.
224+ Audit which connectors are in use across monitored flows . Useful for DLP
225+ impact analysis and premium license planning.
192226
193227```
194- 1. list_store_flows
195- 2. For each flow (skip entries without displayName):
228+ 1. list_store_flows(monitor=true)
229+ (scope to monitored flows — auditing all 1000+ flows is expensive)
230+ 2. For each flow (skip entries without displayName or state=Deleted):
196231 - Split id → environmentName, flowName
197232 - get_store_flow(environmentName, flowName)
198233 - Parse connections: json.loads(record["connections"])
@@ -208,6 +243,15 @@ analysis and premium license planning.
208243 agent cross-references against the inventory
209244```
210245
246+ > ** Scope to monitored flows.** Each flow requires a ` get_store_flow ` call
247+ > to read the ` connections ` JSON. Standard plans have ~ 20 monitored flows —
248+ > manageable. Auditing all flows in a large tenant (1000+) would be very
249+ > expensive in API calls.
250+ >
251+ > ** ` list_store_connections ` ** returns connection instances (who created
252+ > which connection) but NOT connector types per flow. Use it for connection
253+ > counts per environment, not for the connector audit.
254+ >
211255> DLP policy definitions are not available via MCP. The agent builds the
212256> connector inventory; the user provides the DLP classification to
213257> cross-reference against.
@@ -219,17 +263,21 @@ Configure monitoring and alerting for flows at scale.
219263```
220264Enable failure alerts on all critical flows:
2212651. list_store_flows(monitor=true)
222- 2. For each flow (skip entries without displayName):
266+ 2. For each flow (skip entries without displayName or state=Deleted ):
223267 - Split id → environmentName, flowName
224268 - get_store_flow(environmentName, flowName)
225269 - If critical=true AND rule_notify_onfail is not true:
226270 update_store_flow(environmentName, flowName,
227271 rule_notify_onfail=true,
228272 rule_notify_email="oncall@contoso.com")
273+ - If NO flows have critical=true: this is a governance finding.
274+ Recommend the user designate their most important flows as critical
275+ using update_store_flow(critical=true) before configuring alerts.
229276
230277Enable missing-run detection for scheduled flows:
2312781. list_store_flows(monitor=true)
2322792. For each flow where triggerType="Recurrence" (available on list response):
280+ - Skip flows with state="Stopped" or "Suspended" (not expected to run)
233281 - Split id → environmentName, flowName
234282 - get_store_flow(environmentName, flowName)
235283 - If rule_notify_onmissingdays is 0 or not set:
@@ -253,7 +301,7 @@ Bulk-classify flows by connector type, business function, or risk level.
253301```
254302Auto-tag by connector:
2553031. list_store_flows
256- 2. For each flow (skip entries without displayName):
304+ 2. For each flow (skip entries without displayName or state=Deleted ):
257305 - Split id → environmentName, flowName
258306 - get_store_flow(environmentName, flowName)
259307 - Parse connections: json.loads(record["connections"])
@@ -268,23 +316,31 @@ Auto-tag by connector:
268316 tags="<existing tags> #sharepoint #teams")
269317```
270318
271- > ** Tag merge:** ` update_store_flow(tags=...) ` overwrites the entire tags
272- > field. To avoid losing tags from other workflows, always read the current
273- > tags first, append new ones, then write back.
319+ > ** Two tag systems:** Tags shown in ` list_store_flows ` are auto-extracted
320+ > from the flow's ` description ` field (e.g. a maker writes ` #operations ` in
321+ > the PA portal description). Tags set via ` update_store_flow(tags=...) `
322+ > write to a separate field in the Azure Table cache. They are independent —
323+ > writing store tags does not touch the description, and editing the
324+ > description in the portal does not affect store tags.
325+ >
326+ > ** Tag merge:** ` update_store_flow(tags=...) ` overwrites the store tags
327+ > field. To avoid losing tags from other workflows, read the current store
328+ > tags from ` get_store_flow ` first, append new ones, then write back.
274329>
275330> ` get_store_flow ` already has a ` tier ` field (Standard/Premium) computed
276331> by the scanning pipeline. Only use ` update_store_flow(tier=...) ` if you
277332> need to override it.
278333
279334### 7. Maker Offboarding
280335
281- When an employee leaves, identify and reassign their flows and apps.
336+ When an employee leaves, identify their flows and apps, and reassign
337+ Flow Studio governance contacts and notification recipients.
282338
283339```
2843401. get_store_maker(makerKey="<departing-user-aad-oid>")
285341 → check ownerFlowCount, ownerAppCount, deleted status
2863422. list_store_flows → collect all flows
287- 3. For each flow (skip entries without displayName):
343+ 3. For each flow (skip entries without displayName or state=Deleted ):
288344 - Split id → environmentName, flowName
289345 - get_store_flow(environmentName, flowName)
290346 - Parse owners: json.loads(record["owners"])
@@ -302,39 +358,57 @@ When an employee leaves, identify and reassign their flows and apps.
3023586. Report: flows reassigned, flows stopped, apps needing manual reassignment
303359```
304360
361+ > ** What "reassign" means here:** ` update_store_flow ` changes who Flow
362+ > Studio considers the governance contact and who receives Flow Studio
363+ > notifications. It does NOT transfer the actual Power Automate flow
364+ > ownership — that requires the Power Platform admin center or PowerShell.
365+ > Also update ` rule_notify_email ` so failure notifications go to the new
366+ > team instead of the departing employee's email.
367+ >
305368> Power Apps ownership cannot be changed via MCP tools. Report them for
306369> manual reassignment in the Power Apps admin center.
307370
308371### 8. Security Review
309372
310- Identify flows with potential security concerns.
373+ Review flows for potential security concerns using cached store data .
311374
312375```
313- 1. list_store_flows
314- 2. For each flow (skip entries without displayName):
376+ 1. list_store_flows(monitor=true)
377+ 2. For each flow (skip entries without displayName or state=Deleted ):
315378 - Split id → environmentName, flowName
316379 - get_store_flow(environmentName, flowName)
317380 - Parse security: json.loads(record["security"])
318381 - Parse connections: json.loads(record["connections"])
319382 - Read sharingType directly (top-level field, NOT inside security JSON)
320- 3. Flag flows where:
321- - security.triggerRequestAuthenticationType = "All"
322- (no auth on HTTP trigger — open to internet)
323- - sharingType = "Coauthor" (shared with co-authors, broader access)
324- - connections contain HTTP connector (arbitrary outbound requests)
325- - json.loads(referencedResources) points to external URLs
383+ 3. Report findings to user for review
3263844. For reviewed flows:
327385 Read existing tags, append #security-reviewed
328386 update_store_flow(environmentName, flowName, tags="<existing> #security-reviewed")
329387 Do NOT overwrite the security field — it contains structured auth data
330388```
331389
390+ ** Fields available for security review:**
391+
392+ | Field | Where | What it tells you |
393+ | ---| ---| ---|
394+ | ` security.triggerRequestAuthenticationType ` | security JSON | ` "All" ` = HTTP trigger accepts unauthenticated requests |
395+ | ` sharingType ` | top-level | ` "Coauthor" ` = shared with co-authors for editing |
396+ | ` connections ` | connections JSON | Which connectors the flow uses (check for HTTP, custom) |
397+ | ` referencedResources ` | JSON string | SharePoint sites, Teams channels, external URLs the flow accesses |
398+ | ` tier ` | top-level | ` "Premium" ` = uses premium connectors |
399+
400+ > Each organization decides what constitutes a security concern. For example,
401+ > an unauthenticated HTTP trigger is expected for webhook receivers (Stripe,
402+ > GitHub) but may be a risk for internal flows. Review findings in context
403+ > before flagging.
404+
332405### 9. Environment Governance
333406
334407Audit environments for compliance and sprawl.
335408
336409```
3374101. list_store_environments
411+ Skip entries without displayName (tenant-level metadata rows)
3384122. Flag:
339413 - Developer environments (sku="Developer") — should be limited
340414 - Non-managed environments (isManagedEnvironment=false) — less governance
@@ -405,7 +479,7 @@ Fields marked with `*` are also available on `list_store_flows` (cheaper).
405479| ` rule_notify_onmissingdays ` | number | SLA monitoring configured? |
406480| ` rule_notify_email ` | string | Alert recipients |
407481| ` description ` | string | Documentation completeness |
408- | ` tags ` * | string | Classification (overwrite semantics — read-merge-write to append) |
482+ | ` tags ` | string | Classification — ` list_store_flows ` shows description-extracted hashtags only; store tags written by ` update_store_flow ` require ` get_store_flow ` to read back |
409483| ` runPeriodTotal ` * | number | Activity level |
410484| ` runPeriodFailRate ` * | number | Health status |
411485| ` runLast ` | ISO string | Last run timestamp |
0 commit comments