chore: publish from staged

This commit is contained in:
github-actions[bot]
2026-04-30 00:29:51 +00:00
parent fe4436cbe6
commit deffc46f90
479 changed files with 99117 additions and 283 deletions

View File

@@ -0,0 +1,295 @@
---
name: flowstudio-power-automate-mcp
description: >-
Foundation skill for Power Automate via FlowStudio MCP — auth setup, the
reusable MCP helper (Python + Node.js), tool discovery via `list_skills` /
`tool_search`, and oversized-response handling. Load this skill first when
connecting an agent to Power Automate. For specialized workflows, load
`power-automate-build`, `power-automate-debug`, `power-automate-monitoring`
(Pro+), or `power-automate-governance` (Pro+) — each contains the workflow
narrative, this skill provides the plumbing they all rely on. Requires a
FlowStudio MCP subscription or compatible server — see https://mcp.flowstudio.app
metadata:
openclaw:
requires:
env:
- FLOWSTUDIO_MCP_TOKEN
primaryEnv: FLOWSTUDIO_MCP_TOKEN
homepage: https://mcp.flowstudio.app
---
# Power Automate via FlowStudio MCP — Foundation
This skill is the **plumbing layer**. It gives an AI agent a reliable way to
talk to a FlowStudio MCP server, discover what tools are available, and handle
the responses cleanly. The actual workflow narratives live in four specialized
skills that all build on this one.
> **Real debugging examples**: [Expression error in child flow](https://github.com/ninihen1/power-automate-mcp-skills/blob/main/examples/fix-expression-error.md) |
> [Data entry, not a flow bug](https://github.com/ninihen1/power-automate-mcp-skills/blob/main/examples/data-not-flow.md) |
> [Null value crashes child flow](https://github.com/ninihen1/power-automate-mcp-skills/blob/main/examples/null-child-flow.md)
> **Requires:** A [FlowStudio](https://mcp.flowstudio.app) MCP subscription (or
> compatible Power Automate MCP server). You will need:
> - MCP endpoint: `https://mcp.flowstudio.app/mcp` (same for all subscribers)
> - API key / JWT token (`x-api-key` header — NOT Bearer)
> - Power Platform environment name (e.g. `Default-<tenant-guid>`)
---
## Which Skill to Use When
Skills are organized by **use-case intent**, not by which tools they call.
Multiple skills reuse the same underlying tools — pick by what the user is
trying to accomplish.
| The user wants to… | Load this skill |
|---|---|
| Make or change a flow (build new, modify existing, fix a bug, deploy) | **`power-automate-build`** |
| Diagnose why a flow failed (root cause analysis on a failing run) | **`power-automate-debug`** |
| See tenant-wide flow health, failure rates, asset inventory | **`power-automate-monitoring`** *(Pro+)* |
| Tag, audit, classify, score, or offboard flows | **`power-automate-governance`** *(Pro+)* |
| Just connect, set up auth, write the helper, parse responses | this skill (foundation) |
**Same tools, different lenses.** `power-automate-build` and `power-automate-debug`
both call `update_live_flow`, `get_live_flow`, and the run-error tools — they
differ in *direction* (forward vs backward) and *intent* (compose vs diagnose).
`power-automate-monitoring` and `power-automate-governance` both call the Store
tools — they differ in *audience* (ops vs compliance) and *outcome* (read
health vs write metadata). Don't try to memorize "which tools belong to which
skill"; pick the skill by what the user is doing.
---
## Source of Truth
| Priority | Source | Covers |
|----------|--------|--------|
| 1 | **Real API response** | Always trust what the server actually returns |
| 2 | **`tool_search` / `list_skills`** | Authoritative tool schemas, parameter names, types, required flags |
| 3 | **SKILL docs & reference files** | Workflow narrative, response shapes, non-obvious behaviors |
If documentation disagrees with a real API response, the API wins. Tool schemas
in this skill (or any other) may lag the server — call `tool_search` to confirm
the current shape before invoking a tool you haven't used recently.
---
## How Agents Discover Tools
The FlowStudio MCP server (v1.1.5+) exposes two **non-billable** meta-tools that
let an agent load only the tools relevant to the current task. Use these in
preference to `tools/list` (which loads all 30+ schemas at once) or guessing
tool names.
| Meta-tool | When to call |
|---|---|
| `list_skills` | Cold start — see the available bundles (`build-flow`, `debug-flow`, `monitor-flow`, `discover`, `governance`) and pick one |
| `tool_search` with `query: "skill:<name>"` | Load the full schema set for one bundle (e.g. `skill:debug-flow`) |
| `tool_search` with `query: "select:tool1,tool2"` | Load specific tools by name (e.g. when chaining across bundles) |
| `tool_search` with `query: "<keywords>"` | Free-text search when the user request is ambiguous (e.g. `"cancel run"`) |
The server's `tool_search` bundles are intentionally **narrower than this
skill family** — they're starter packs of the most-likely-needed tools per
intent. A workflow skill (e.g. `power-automate-debug`) may pull a bundle and
then call `tool_search` again for additional tools as the workflow progresses.
```python
# Cold start — pick a bundle by intent
skills = mcp("list_skills", {})
# [{"name": "debug-flow", "description": "Investigate why a flow is failing...",
# "tools": ["get_live_flow_runs", "get_live_flow_run_error", ...]}, ...]
# Load schemas for the bundle
debug_tools = mcp("tool_search", {"query": "skill:debug-flow"})
```
---
## Recommended Language: Python or Node.js
All examples in this skill family use **Python with `urllib.request`**
(stdlib — no `pip install` needed). **Node.js** is an equally valid choice:
`fetch` is built-in from Node 18+, JSON handling is native, and async/await
maps cleanly onto the request-response pattern of MCP tool calls — making it
a natural fit for teams already working in a JavaScript/TypeScript stack.
| Language | Verdict | Notes |
|---|---|---|
| **Python** | Recommended | Clean JSON handling, no escaping issues, all skill examples use it |
| **Node.js (≥ 18)** | Recommended | Native `fetch` + `JSON.stringify`/`JSON.parse`; no extra packages |
| PowerShell | Avoid for flow operations | `ConvertTo-Json -Depth` silently truncates nested definitions; quoting and escaping break complex payloads. Acceptable for a quick connectivity smoke-test but not for building or updating flows. |
| cURL / Bash | Possible but fragile | Shell-escaping nested JSON is error-prone; no native JSON parser |
> **TL;DR — use the Core MCP Helper (Python or Node.js) below.** Both handle
> JSON-RPC framing, auth, and response parsing in a single reusable function.
---
## Core MCP Helper (Python)
Use this helper throughout all subsequent operations:
```python
import json, urllib.request
TOKEN = "<YOUR_JWT_TOKEN>"
MCP = "https://mcp.flowstudio.app/mcp"
def mcp(tool, args, cid=1):
payload = {"jsonrpc": "2.0", "method": "tools/call", "id": cid,
"params": {"name": tool, "arguments": args}}
req = urllib.request.Request(MCP, data=json.dumps(payload).encode(),
headers={"x-api-key": TOKEN, "Content-Type": "application/json",
"User-Agent": "FlowStudio-MCP/1.0"})
try:
resp = urllib.request.urlopen(req, timeout=120)
except urllib.error.HTTPError as e:
body = e.read().decode("utf-8", errors="replace")
raise RuntimeError(f"MCP HTTP {e.code}: {body[:200]}") from e
raw = json.loads(resp.read())
if "error" in raw:
raise RuntimeError(f"MCP error: {json.dumps(raw['error'])}")
text = raw["result"]["content"][0]["text"]
return json.loads(text)
```
> **Common auth errors:**
> - HTTP 401/403 → token is missing, expired, or malformed. Get a fresh JWT from [mcp.flowstudio.app](https://mcp.flowstudio.app).
> - HTTP 400 → malformed JSON-RPC payload. Check `Content-Type: application/json` and body structure.
> - `MCP error: {"code": -32602, ...}` → wrong or missing tool arguments. Call `tool_search` with `select:<toolname>` to confirm the schema.
---
## Core MCP Helper (Node.js)
Equivalent helper for Node.js 18+ (built-in `fetch` — no packages required):
```js
const TOKEN = "<YOUR_JWT_TOKEN>";
const MCP = "https://mcp.flowstudio.app/mcp";
async function mcp(tool, args, cid = 1) {
const payload = {
jsonrpc: "2.0",
method: "tools/call",
id: cid,
params: { name: tool, arguments: args },
};
const res = await fetch(MCP, {
method: "POST",
headers: {
"x-api-key": TOKEN,
"Content-Type": "application/json",
"User-Agent": "FlowStudio-MCP/1.0",
},
body: JSON.stringify(payload),
});
if (!res.ok) {
const body = await res.text();
throw new Error(`MCP HTTP ${res.status}: ${body.slice(0, 200)}`);
}
const raw = await res.json();
if (raw.error) throw new Error(`MCP error: ${JSON.stringify(raw.error)}`);
return JSON.parse(raw.result.content[0].text);
}
```
> Requires Node.js 18+. For older Node, replace `fetch` with `https.request`
> from the stdlib or install `node-fetch`.
---
## Verify the Connection
A 3-line smoke test that confirms the token, endpoint, and helper all work:
```python
skills = mcp("list_skills", {})
print(f"Connected — {len(skills)} skill bundles available:",
[s["name"] for s in skills])
```
Expected output:
```text
Connected — 5 skill bundles available: ['build-flow', 'debug-flow', 'monitor-flow', 'discover', 'governance']
```
If this fails, see the **Common auth errors** note above. If it succeeds, hand
off to the workflow skill matching the user's intent.
---
## Handling Oversized Responses
Some MCP tool responses are large enough to overflow the agent's context window:
| Tool | Typical size | Cause |
|---|---|---|
| `describe_live_connector` | 100-600 KB | Full Swagger spec for a connector |
| `get_live_flow_run_action_outputs` (no `actionName`) | 50 KB several MB | All actions × all foreach iterations |
| `get_live_flow` (large flows) | 50-500 KB | Deeply nested branches |
| `list_live_flows` (large tenants) | 50-200 KB | Hundreds of flow records |
### When the harness spills to a file
Agent harnesses (Claude Code, VS Code Copilot, etc.) save oversized responses
to a temp file (e.g. `tool-results/mcp-flowstudio-describe_live_connector-NNNN.txt`)
and return the path instead of the inline JSON. The file is **double-wrapped**
the outer MCP envelope plus the inner JSON-escaped payload:
```text
[{"type":"text","text":"<JSON-escaped payload>"}]
```
Two parses to reach a usable object:
```python
import json
with open(path) as f:
raw = json.loads(f.read())
payload = json.loads(raw[0]["text"])
```
```powershell
$payload = ((Get-Content $path -Raw | ConvertFrom-Json)[0].text) | ConvertFrom-Json
```
### Rules of thumb
1. **Extract, don't echo.** Pull the specific field(s) you need (one `operationId`, one action's outputs) and discard the rest before reasoning about it.
2. **Always pass `actionName` to `get_live_flow_run_action_outputs`.** Omitting it fetches every action × every iteration — fine for offline debug scripts, dangerous for an agent that ingests the whole response.
3. **Reuse the spill file within a session.** Refetching the same connector swagger costs 30+ seconds and produces another spill — cache the path.
4. **Don't grep the spill file for JSON keys directly.** Strings are JSON-escaped inside the file (`\"OperationId\":`), so a plain grep for `"OperationId":` will not match. Parse first, then filter.
5. **Summarize tool output to the user.** Echo `name + state + trigger` for flow lists and `actionName + status + code` for run errors — not raw JSON, unless asked.
```python
# Good — drill into one operation in a connector swagger
conn = mcp("describe_live_connector", {"environmentName": ENV, "connectorName": "shared_sharepointonline"})
op = conn["properties"]["swagger"]["paths"]["/datasets/{dataset}/tables/{table}/items"]["get"]
print(op["operationId"], "", op.get("summary"))
# Bad — keeping the whole 500 KB swagger in context
print(json.dumps(conn, indent=2)) # don't do this
```
---
## Auth & Connection Notes
| Field | Value |
|---|---|
| Auth header | `x-api-key: <JWT>`**not** `Authorization: Bearer` |
| Token format | Plain JWT — do not strip, alter, or prefix it |
| Timeout | Use ≥ 120 s for `get_live_flow_run_action_outputs` (large outputs) |
| Environment name | `Default-<tenant-guid>` (find it via `list_live_environments` or `list_live_flows` response) |
---
## Reference Files
- [MCP-BOOTSTRAP.md](references/MCP-BOOTSTRAP.md) — endpoint, auth, request/response format (read this first)
- [tool-reference.md](references/tool-reference.md) — response shapes and behavioral notes (parameters are in `tool_search`)
- [action-types.md](references/action-types.md) — Power Automate action type patterns
- [connection-references.md](references/connection-references.md) — connector reference guide

View File

@@ -0,0 +1,53 @@
# MCP Bootstrap — Quick Reference
Everything an agent needs to start calling the FlowStudio MCP server.
```
Endpoint: https://mcp.flowstudio.app/mcp
Protocol: JSON-RPC 2.0 over HTTP POST
Transport: Streamable HTTP — single POST per request, no SSE, no WebSocket
Auth: x-api-key header with JWT token (NOT Bearer)
```
## Required Headers
```
Content-Type: application/json
x-api-key: <token>
User-Agent: FlowStudio-MCP/1.0 ← required, or Cloudflare blocks you
```
## Step 1 — Discover Tools
```json
POST {"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}
```
Returns all tools with names, descriptions, and input schemas.
Free — not counted against plan limits.
## Step 2 — Call a Tool
```json
POST {"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"<tool_name>","arguments":{...}}}
```
## Response Shape
```
Success → {"result":{"content":[{"type":"text","text":"<JSON string>"}]}}
Error → {"result":{"content":[{"type":"text","text":"{\"error\":{...}}"}]}}
```
Always parse `result.content[0].text` as JSON to get the actual data.
## Key Tips
- Tool results are JSON strings inside the text field — **double-parse needed**
- `"error"` field in parsed body: `null` = success, object = failure
- `environmentName` is required for most tools, but **not** for:
`list_live_environments`, `list_live_connections`, `list_store_flows`,
`list_store_environments`, `list_store_makers`, `get_store_maker`,
`list_store_power_apps`, `list_store_connections`
- When in doubt, check the `required` array in each tool's schema from `tools/list`

View File

@@ -0,0 +1,79 @@
# FlowStudio MCP — Action Types Reference
Compact lookup for recognising action types returned by `get_live_flow`.
Use this to **read and understand** existing flow definitions.
> For full copy-paste construction patterns, see the `flowstudio-power-automate-build` skill.
---
## How to Read a Flow Definition
Every action has `"type"`, `"runAfter"`, and `"inputs"`. The `runAfter` object
declares dependencies: `{"Previous": ["Succeeded"]}`. Valid statuses:
`Succeeded`, `Failed`, `Skipped`, `TimedOut`.
---
## Action Type Quick Reference
| Type | Purpose | Key fields to inspect | Output reference |
|---|---|---|---|
| `Compose` | Store/transform a value | `inputs` (any expression) | `outputs('Name')` |
| `InitializeVariable` | Declare a variable | `inputs.variables[].{name, type, value}` | `variables('name')` |
| `SetVariable` | Update a variable | `inputs.{name, value}` | `variables('name')` |
| `IncrementVariable` | Increment a numeric variable | `inputs.{name, value}` | `variables('name')` |
| `AppendToArrayVariable` | Push to an array variable | `inputs.{name, value}` | `variables('name')` |
| `If` | Conditional branch | `expression.and/or`, `actions`, `else.actions` | — |
| `Switch` | Multi-way branch | `expression`, `cases.{case, actions}`, `default` | — |
| `Foreach` | Loop over array | `foreach`, `actions`, `operationOptions` | `item()` / `items('Name')` |
| `Until` | Loop until condition | `expression`, `limit.{count, timeout}`, `actions` | — |
| `Wait` | Delay | `inputs.interval.{count, unit}` | — |
| `Scope` | Group / try-catch | `actions` (nested action map) | `result('Name')` |
| `Terminate` | End run | `inputs.{runStatus, runError}` | — |
| `OpenApiConnection` | Connector call (SP, Outlook, Teams…) | `inputs.host.{apiId, connectionName, operationId}`, `inputs.parameters` | `outputs('Name')?['body/...']` |
| `OpenApiConnectionWebhook` | Webhook wait (approvals, adaptive cards) | same as above | `body('Name')?['...']` |
| `Http` | External HTTP call | `inputs.{method, uri, headers, body}` | `outputs('Name')?['body']` |
| `Response` | Return to HTTP caller | `inputs.{statusCode, headers, body}` | — |
| `Query` | Filter array | `inputs.{from, where}` | `body('Name')` (filtered array) |
| `Select` | Reshape/project array | `inputs.{from, select}` | `body('Name')` (projected array) |
| `Table` | Array → CSV/HTML string | `inputs.{from, format, columns}` | `body('Name')` (string) |
| `ParseJson` | Parse JSON with schema | `inputs.{content, schema}` | `body('Name')?['field']` |
| `Expression` | Built-in function (e.g. ConvertTimeZone) | `kind`, `inputs` | `body('Name')` |
---
## Connector Identification
When you see `type: OpenApiConnection`, identify the connector from `host.apiId`:
| apiId suffix | Connector |
|---|---|
| `shared_sharepointonline` | SharePoint |
| `shared_office365` | Outlook / Office 365 |
| `shared_teams` | Microsoft Teams |
| `shared_approvals` | Approvals |
| `shared_office365users` | Office 365 Users |
| `shared_flowmanagement` | Flow Management |
The `operationId` tells you the specific operation (e.g. `GetItems`, `SendEmailV2`,
`PostMessageToConversation`). The `connectionName` maps to a GUID in
`properties.connectionReferences`.
---
## Common Expressions (Reading Cheat Sheet)
| Expression | Meaning |
|---|---|
| `@outputs('X')?['body/value']` | Array result from connector action X |
| `@body('X')` | Direct body of action X (Query, Select, ParseJson) |
| `@item()?['Field']` | Current loop item's field |
| `@triggerBody()?['Field']` | Trigger payload field |
| `@variables('name')` | Variable value |
| `@coalesce(a, b)` | First non-null of a, b |
| `@first(array)` | First element (null if empty) |
| `@length(array)` | Array count |
| `@empty(value)` | True if null/empty string/empty array |
| `@union(a, b)` | Merge arrays — **first wins** on duplicates |
| `@result('Scope')` | Array of action outcomes inside a Scope |

View File

@@ -0,0 +1,115 @@
# FlowStudio MCP — Connection References
Connection references wire a flow's connector actions to real authenticated
connections in the Power Platform. They are required whenever you call
`update_live_flow` with a definition that uses connector actions.
---
## Structure in a Flow Definition
```json
{
"properties": {
"definition": { ... },
"connectionReferences": {
"shared_sharepointonline": {
"connectionName": "shared-sharepointonl-62599557c-1f33-4aec-b4c0-a6e4afcae3be",
"id": "/providers/Microsoft.PowerApps/apis/shared_sharepointonline",
"displayName": "SharePoint"
},
"shared_office365": {
"connectionName": "shared-office365-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"id": "/providers/Microsoft.PowerApps/apis/shared_office365",
"displayName": "Office 365 Outlook"
}
}
}
}
```
Keys are **logical reference names** (e.g. `shared_sharepointonline`).
These match the `connectionName` field inside each action's `host` block.
---
## Finding Connection GUIDs
Call `get_live_flow` on **any existing flow** that uses the same connection
and copy the `connectionReferences` block. The GUID after the connector prefix is
the connection instance owned by the authenticating user.
```python
flow = mcp("get_live_flow", environmentName=ENV, flowName=EXISTING_FLOW_ID)
conn_refs = flow["properties"]["connectionReferences"]
# conn_refs["shared_sharepointonline"]["connectionName"]
# → "shared-sharepointonl-62599557c-1f33-4aec-b4c0-a6e4afcae3be"
```
> ⚠️ Connection references are **user-scoped**. If a connection is owned
> by another account, `update_live_flow` will return 403
> `ConnectionAuthorizationFailed`. You must use a connection belonging to
> the account whose token is in the `x-api-key` header.
---
## Passing `connectionReferences` to `update_live_flow`
```python
result = mcp("update_live_flow",
environmentName=ENV,
flowName=FLOW_ID,
definition=modified_definition,
connectionReferences={
"shared_sharepointonline": {
"connectionName": "shared-sharepointonl-62599557c-1f33-4aec-b4c0-a6e4afcae3be",
"id": "/providers/Microsoft.PowerApps/apis/shared_sharepointonline"
}
}
)
```
Only include connections that the definition actually uses.
---
## Common Connector API IDs
| Service | API ID |
|---|---|
| SharePoint Online | `/providers/Microsoft.PowerApps/apis/shared_sharepointonline` |
| Office 365 Outlook | `/providers/Microsoft.PowerApps/apis/shared_office365` |
| Microsoft Teams | `/providers/Microsoft.PowerApps/apis/shared_teams` |
| OneDrive for Business | `/providers/Microsoft.PowerApps/apis/shared_onedriveforbusiness` |
| Azure AD | `/providers/Microsoft.PowerApps/apis/shared_azuread` |
| HTTP with Azure AD | `/providers/Microsoft.PowerApps/apis/shared_webcontents` |
| SQL Server | `/providers/Microsoft.PowerApps/apis/shared_sql` |
| Dataverse | `/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps` |
| Azure Blob Storage | `/providers/Microsoft.PowerApps/apis/shared_azureblob` |
| Approvals | `/providers/Microsoft.PowerApps/apis/shared_approvals` |
| Office 365 Users | `/providers/Microsoft.PowerApps/apis/shared_office365users` |
| Flow Management | `/providers/Microsoft.PowerApps/apis/shared_flowmanagement` |
---
## Teams Adaptive Card Dual-Connection Requirement
Flows that send adaptive cards **and** post follow-up messages require two
separate Teams connections:
```json
"connectionReferences": {
"shared_teams": {
"connectionName": "shared-teams-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"id": "/providers/Microsoft.PowerApps/apis/shared_teams"
},
"shared_teams_1": {
"connectionName": "shared-teams-yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"id": "/providers/Microsoft.PowerApps/apis/shared_teams"
}
}
```
Both can point to the **same underlying Teams account** but must be registered
as two distinct connection references. The webhook (`OpenApiConnectionWebhook`)
uses `shared_teams` and subsequent message actions use `shared_teams_1`.

View File

@@ -0,0 +1,499 @@
# FlowStudio MCP — Tool Response Catalog
Response shapes and behavioral notes for the FlowStudio Power Automate MCP server.
> **For tool names and parameters**: Always call `tools/list` on the server.
> It returns the authoritative, up-to-date schema for every tool.
> This document covers what `tools/list` does NOT tell you: **response shapes**
> and **non-obvious behaviors** discovered through real usage.
---
## Source of Truth
| Priority | Source | Covers |
|----------|--------|--------|
| 1 | **Real API response** | Always trust what the server actually returns |
| 2 | **`tools/list`** | Tool names, parameter names, types, required flags |
| 3 | **This document** | Response shapes, behavioral notes, gotchas |
> If this document disagrees with `tools/list` or real API behavior,
> the API wins. Update this document accordingly.
---
## Environment & Tenant Discovery
### `list_live_environments`
Response: direct array of environments.
```json
[
{
"id": "Default-26e65220-5561-46ef-9783-ce5f20489241",
"displayName": "FlowStudio (default)",
"sku": "Production",
"location": "australia",
"state": "Enabled",
"isDefault": true,
"isAdmin": true,
"isMember": true,
"createdTime": "2023-08-18T00:41:05Z"
}
]
```
> Use the `id` value as `environmentName` in all other tools.
### `list_store_environments`
Same shape as `list_live_environments` but read from cache (faster).
---
## Connection Discovery
### `list_live_connections`
Response: wrapper object with `connections` array.
```json
{
"connections": [
{
"id": "shared-office365-9f9d2c8e-55f1-49c9-9f9c-1c45d1fbbdce",
"displayName": "user@contoso.com",
"connectorName": "shared_office365",
"createdBy": "User Name",
"statuses": [{"status": "Connected"}],
"createdTime": "2024-03-12T21:23:55.206815Z"
}
],
"totalCount": 56,
"error": null
}
```
> **Key field**: `id` is the `connectionName` value used in `connectionReferences`.
>
> **Key field**: `connectorName` maps to apiId:
> `"/providers/Microsoft.PowerApps/apis/" + connectorName`
>
> Filter by status: `statuses[0].status == "Connected"`.
>
> **Note**: `tools/list` marks `environmentName` as optional, but the server
> returns `MissingEnvironmentFilter` (HTTP 400) if you omit it. Always pass
> `environmentName`.
### `list_store_connections`
Same connection data from cache.
---
## Flow Discovery & Listing
### `list_live_flows`
Response: wrapper object with `flows` array.
```json
{
"mode": "owner",
"flows": [
{
"id": "0757041a-8ef2-cf74-ef06-06881916f371",
"displayName": "My Flow",
"state": "Started",
"triggerType": "Request",
"triggerKind": "Http",
"createdTime": "2023-08-18T01:18:17Z",
"lastModifiedTime": "2023-08-18T12:47:42Z",
"owners": "<aad-object-id>",
"definitionAvailable": true
}
],
"totalCount": 100,
"error": null
}
```
> Access via `result["flows"]`. `id` is a plain UUID --- use directly as `flowName`.
>
> `mode` indicates the access scope used (`"owner"` or `"admin"`).
### `list_store_flows`
Response: **direct array** (no wrapper).
```json
[
{
"id": "3991358a-f603-e49d-b1ed-a9e4f72e2dcb.0757041a-8ef2-cf74-ef06-06881916f371",
"displayName": "Admin | Sync Template v3 (Solutions)",
"state": "Started",
"triggerType": "OpenApiConnectionWebhook",
"environmentName": "3991358a-f603-e49d-b1ed-a9e4f72e2dcb",
"runPeriodTotal": 100,
"createdTime": "2023-08-18T01:18:17Z",
"lastModifiedTime": "2023-08-18T12:47:42Z"
}
]
```
> **`id` format**: `<environmentId>.<flowId>` --- split on the first `.` to extract the flow UUID:
> `flow_id = item["id"].split(".", 1)[1]`
### `get_store_flow`
Response: single flow metadata from cache (selected fields).
```json
{
"id": "<environmentId>.<flowId>",
"displayName": "My Flow",
"state": "Started",
"triggerType": "Recurrence",
"runPeriodTotal": 100,
"runPeriodFailRate": 0.1,
"runPeriodSuccessRate": 0.9,
"runPeriodFails": 10,
"runPeriodSuccess": 90,
"runPeriodDurationAverage": 29410.8,
"runPeriodDurationMax": 158900.0,
"runError": "{\"code\": \"EACCES\", ...}",
"description": "Flow description",
"tier": "Premium",
"complexity": "{...}",
"actions": 42,
"connections": ["sharepointonline", "office365"],
"owners": ["user@contoso.com"],
"createdBy": "user@contoso.com"
}
```
> `runPeriodDurationAverage` / `runPeriodDurationMax` are in **milliseconds** (divide by 1000).
> `runError` is a **JSON string** --- parse with `json.loads()`.
---
## Flow Definition (Live API)
### `get_live_flow`
Response: full flow definition from PA API.
```json
{
"name": "<flow-guid>",
"properties": {
"displayName": "My Flow",
"state": "Started",
"definition": {
"triggers": { "..." },
"actions": { "..." },
"parameters": { "..." }
},
"connectionReferences": { "..." }
}
}
```
### `update_live_flow`
**Create mode**: Omit `flowName` --- creates a new flow. `definition` and `displayName` required.
**Update mode**: Provide `flowName` --- PATCHes existing flow.
Response:
```json
{
"created": false,
"flowKey": "<environmentId>.<flowId>",
"updated": ["definition", "connectionReferences"],
"displayName": "My Flow",
"state": "Started",
"definition": { "...full definition..." },
"error": null
}
```
> `error` is **always present** but may be `null`. Check `result.get("error") is not None`.
>
> On create: `created` is the new flow GUID (string). On update: `created` is `false`.
>
> `description` is **always required** (create and update).
### `add_live_flow_to_solution`
Migrates a non-solution flow into a solution. Returns error if already in a solution.
---
## Run History & Monitoring
### `get_live_flow_runs`
Response: direct array of runs (newest first).
```json
[{
"name": "<run-id>",
"status": "Succeeded|Failed|Running|Cancelled",
"startTime": "2026-02-25T06:13:38Z",
"endTime": "2026-02-25T06:14:02Z",
"triggerName": "Recurrence",
"error": null
}]
```
> `top` defaults to **30** and auto-paginates for higher values. Set `top: 300`
> for 24-hour coverage on flows running every 5 minutes.
>
> Run ID field is **`name`** (not `runName`). Use this value as the `runName`
> parameter in other tools.
### `get_live_flow_run_error`
Response: structured error breakdown for a failed run.
```json
{
"runName": "08584296068667933411438594643CU15",
"failedActions": [
{
"actionName": "Apply_to_each_prepare_workers",
"status": "Failed",
"error": {"code": "ActionFailed", "message": "An action failed."},
"code": "ActionFailed",
"startTime": "2026-02-25T06:13:52Z",
"endTime": "2026-02-25T06:15:24Z"
},
{
"actionName": "HTTP_find_AD_User_by_Name",
"status": "Failed",
"code": "NotSpecified",
"startTime": "2026-02-25T06:14:01Z",
"endTime": "2026-02-25T06:14:05Z"
}
],
"allActions": [
{"actionName": "Apply_to_each", "status": "Skipped"},
{"actionName": "Compose_WeekEnd", "status": "Succeeded"},
{"actionName": "HTTP_find_AD_User_by_Name", "status": "Failed"}
]
}
```
> `failedActions` is ordered outer-to-inner --- the **last entry is the root cause**.
> Use `failedActions[-1]["actionName"]` as the starting point for diagnosis.
### `get_live_flow_run_action_outputs`
Response: array of action detail objects.
```json
[
{
"actionName": "Compose_WeekEnd_now",
"status": "Succeeded",
"startTime": "2026-02-25T06:13:52Z",
"endTime": "2026-02-25T06:13:52Z",
"error": null,
"inputs": "Mon, 25 Feb 2026 06:13:52 GMT",
"outputs": "Mon, 25 Feb 2026 06:13:52 GMT"
}
]
```
> **`actionName` is optional**: omit it to return ALL actions in the run;
> provide it to return a single-element array for that action only.
>
> Outputs can be very large (50 MB+) for bulk-data actions. Use 120s+ timeout.
---
## Run Control
### `resubmit_live_flow_run`
Response: `{ flowKey, resubmitted: true, runName, triggerName }`
### `cancel_live_flow_run`
Cancels a `Running` flow run.
> Do NOT cancel runs waiting for an adaptive card response --- status `Running`
> is normal while a Teams card is awaiting user input.
---
## HTTP Trigger Tools
### `get_live_flow_http_schema`
Response keys:
```
flowKey - Flow GUID
displayName - Flow display name
triggerName - Trigger action name (e.g. "manual")
triggerType - Trigger type (e.g. "Request")
triggerKind - Trigger kind (e.g. "Http")
requestMethod - HTTP method (e.g. "POST")
relativePath - Relative path configured on the trigger (if any)
requestSchema - JSON schema the trigger expects as POST body
requestHeaders - Headers the trigger expects
responseSchemas - Array of JSON schemas defined on Response action(s)
responseSchemaCount - Number of Response actions that define output schemas
```
> The request body schema is in `requestSchema` (not `triggerSchema`).
### `get_live_flow_trigger_url`
Returns the signed callback URL for HTTP-triggered flows. Response includes
`flowKey`, `triggerName`, `triggerType`, `triggerKind`, `triggerMethod`, `triggerUrl`.
### `trigger_live_flow`
Response keys: `flowKey`, `triggerName`, `triggerUrl`, `requiresAadAuth`, `authType`,
`responseStatus`, `responseBody`.
> **Only works for `Request` (HTTP) triggers.** Returns an error for Recurrence
> and other trigger types: `"only HTTP Request triggers can be invoked via this tool"`.
> `Button`-kind triggers return `ListCallbackUrlOperationBlocked`.
>
> `responseStatus` + `responseBody` contain the flow's Response action output.
> AAD-authenticated triggers are handled automatically.
>
> **Content-type note**: The body is sent as `application/octet-stream` (raw),
> not `application/json`. Flows with a trigger schema that has `required` fields
> will reject the request with `InvalidRequestContent` (400) because PA validates
> `Content-Type` before parsing against the schema. Flows without a schema, or
> flows designed to accept raw input (e.g. Baker-pattern flows that parse the body
> internally), will work fine. The flow receives the JSON as base64-encoded
> `$content` with `$content-type: application/octet-stream`.
---
## Flow State Management
### `set_live_flow_state`
Start or stop a Power Automate flow via the live PA API. Does **not** require
a Power Clarity workspace — works for any flow the impersonated account can access.
Reads the current state first and only issues the start/stop call if a change is
actually needed.
Parameters: `environmentName`, `flowName`, `state` (`"Started"` | `"Stopped"`) — all required.
Response:
```json
{
"flowName": "6321ab25-7eb0-42df-b977-e97d34bcb272",
"environmentName": "Default-26e65220-...",
"requestedState": "Started",
"actualState": "Started"
}
```
> **Use this tool** — not `update_live_flow` — to start or stop a flow.
> `update_live_flow` only changes displayName/definition; the PA API ignores
> state passed through that endpoint.
### `set_store_flow_state`
Start or stop a flow via the live PA API **and** persist the updated state back
to the Power Clarity cache. Same parameters as `set_live_flow_state` but requires
a Power Clarity workspace.
Response (different shape from `set_live_flow_state`):
```json
{
"flowKey": "<environmentId>.<flowId>",
"requestedState": "Stopped",
"currentState": "Stopped",
"flow": { /* full gFlows record, same shape as get_store_flow */ }
}
```
> Prefer `set_live_flow_state` when you only need to toggle state — it's
> simpler and has no subscription requirement.
>
> Use `set_store_flow_state` when you need the cache updated immediately
> (without waiting for the next daily scan) AND want the full updated
> governance record back in the same call — useful for workflows that
> stop a flow and immediately tag or inspect it.
---
## Store Tools --- FlowStudio for Teams Only
### `get_store_flow_summary`
Response: aggregated run statistics.
```json
{
"totalRuns": 100,
"failRuns": 10,
"failRate": 0.1,
"averageDurationSeconds": 29.4,
"maxDurationSeconds": 158.9,
"firstFailRunRemediation": "<hint or null>"
}
```
### `get_store_flow_runs`
Cached run history for the last N days with duration and remediation hints.
### `get_store_flow_errors`
Cached failed-only runs with failed action names and remediation hints.
### `get_store_flow_trigger_url`
Trigger URL from cache (instant, no PA API call).
### `update_store_flow`
Update governance metadata (description, tags, monitor flag, notification rules, business impact).
### `list_store_makers` / `get_store_maker`
Maker (citizen developer) discovery and detail.
### `list_store_power_apps`
List all Power Apps canvas apps from the cache.
---
## Behavioral Notes
Non-obvious behaviors discovered through real API usage. These are things
`tools/list` cannot tell you.
### `get_live_flow_run_action_outputs`
- **`actionName` is optional**: omit to get all actions, provide to get one.
This changes the response from N elements to 1 element (still an array).
- Outputs can be 50 MB+ for bulk-data actions --- always use 120s+ timeout.
### `update_live_flow`
- `description` is **always required** (create and update modes).
- `error` key is **always present** in response --- `null` means success.
Do NOT check `if "error" in result`; check `result.get("error") is not None`.
- On create, `created` = new flow GUID (string). On update, `created` = `false`.
- **Cannot change flow state.** Only updates displayName, definition, and
connectionReferences. Use `set_live_flow_state` to start/stop a flow.
### `trigger_live_flow`
- **Only works for HTTP Request triggers.** Returns error for Recurrence, connector,
and other trigger types.
- AAD-authenticated triggers are handled automatically (impersonated Bearer token).
### `get_live_flow_runs`
- `top` defaults to **30** with automatic pagination for higher values.
- Run ID field is `name`, not `runName`. Use this value as `runName` in other tools.
- Runs are returned newest-first.
### Teams `PostMessageToConversation` (via `update_live_flow`)
- **"Chat with Flow bot"**: `body/recipient` = `"user@domain.com;"` (string with trailing semicolon).
- **"Channel"**: `body/recipient` = `{"groupId": "...", "channelId": "..."}` (object).
- `poster`: `"Flow bot"` for Workflows bot identity, `"User"` for user identity.
### `list_live_connections`
- `id` is the value you need for `connectionName` in `connectionReferences`.
- `connectorName` maps to apiId: `"/providers/Microsoft.PowerApps/apis/" + connectorName`.