From 9c81ea6258f3cd7fab65f282a1115077cc3ebe02 Mon Sep 17 00:00:00 2001 From: Catherine Han Date: Fri, 6 Mar 2026 09:47:37 +1100 Subject: [PATCH 1/2] feat: add power-automate-mcp skill Connect to and operate Power Automate cloud flows via a FlowStudio MCP server. Includes tool reference, action types, connection references, and bootstrap guide. --- skills/power-automate-mcp/SKILL.md | 449 ++++++++++++++++++ .../references/MCP-BOOTSTRAP.md | 53 +++ .../references/action-types.md | 79 +++ .../references/connection-references.md | 115 +++++ .../references/tool-reference.md | 441 +++++++++++++++++ 5 files changed, 1137 insertions(+) create mode 100644 skills/power-automate-mcp/SKILL.md create mode 100644 skills/power-automate-mcp/references/MCP-BOOTSTRAP.md create mode 100644 skills/power-automate-mcp/references/action-types.md create mode 100644 skills/power-automate-mcp/references/connection-references.md create mode 100644 skills/power-automate-mcp/references/tool-reference.md diff --git a/skills/power-automate-mcp/SKILL.md b/skills/power-automate-mcp/SKILL.md new file mode 100644 index 000000000..15afdebcf --- /dev/null +++ b/skills/power-automate-mcp/SKILL.md @@ -0,0 +1,449 @@ +--- +name: power-automate-mcp +description: >- + Connect to and operate Power Automate cloud flows via a FlowStudio MCP server. + Use when asked to: list flows, read a flow definition, check run history, inspect + action outputs, resubmit a run, cancel a running flow, view connections, get a + trigger URL, validate a definition, monitor flow health, or any task that requires + talking to the Power Automate API through an MCP tool. Also use for Power Platform + environment discovery and connection management. Requires a FlowStudio MCP + subscription or compatible server — see https://mcp.flowstudio.app +--- + +# Power Automate via FlowStudio MCP + +This skill lets AI agents read, monitor, and operate Microsoft Power Automate +cloud flows programmatically through a **FlowStudio MCP server** — no browser, +no UI, no manual steps. + +> **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-`) + +--- + +## 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 | **SKILL docs & reference files** | Response shapes, behavioral notes, workflow recipes | + +> **Start every new session with `tools/list`.** +> It returns the authoritative, up-to-date schema for every tool — parameter names, +> types, and required flags. The SKILL docs cover what `tools/list` cannot tell you: +> response shapes, non-obvious behaviors, and end-to-end workflow patterns. +> +> If any documentation disagrees with `tools/list` or a real API response, +> the API wins. + +--- + +## Recommended Language: Python or Node.js + +All examples in this skill and the companion build / debug skills 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 the async/await model 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`; async/await fits MCP call patterns well; no extra packages needed | +| PowerShell | ⚠️ Avoid for flow operations | `ConvertTo-Json -Depth` silently truncates nested definitions; quoting and escaping break complex payloads. Acceptable for a quick `tools/list` discovery call 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. + +--- + +## What You Can Do + +FlowStudio MCP has two access tiers. **FlowStudio for Teams** subscribers get +both the fast Azure-table store (cached snapshot data + governance metadata) and +full live Power Automate API access. **MCP-only subscribers** get the live tools — +more than enough to build, debug, and operate flows. + +### Live Tools — Available to All MCP Subscribers + +| Tool | What it does | +|---|---| +| `list_live_flows` | List flows in an environment directly from the PA API (always current) | +| `list_live_environments` | List all Power Platform environments visible to the service account | +| `list_live_connections` | List all connections in an environment from the PA API | +| `get_live_flow` | Fetch the complete flow definition (triggers, actions, parameters) | +| `get_live_flow_http_schema` | Inspect the JSON body schema and response schemas of an HTTP-triggered flow | +| `get_live_flow_trigger_url` | Get the current signed callback URL for an HTTP-triggered flow | +| `trigger_live_flow` | POST to an HTTP-triggered flow's callback URL (AAD auth handled automatically) | +| `update_live_flow` | Create a new flow or patch an existing definition in one call | +| `add_live_flow_to_solution` | Migrate a non-solution flow into a solution | +| `get_live_flow_runs` | List recent run history with status, start/end times, and errors | +| `get_live_flow_run_error` | Get structured error details (per-action) for a failed run | +| `get_live_flow_run_action_outputs` | Inspect inputs/outputs of any action (or every foreach iteration) in a run | +| `resubmit_live_flow_run` | Re-run a failed or cancelled run using its original trigger payload | +| `cancel_live_flow_run` | Cancel a currently running flow execution | + +### Store Tools — FlowStudio for Teams Subscribers Only + +These tools read from (and write to) the FlowStudio Azure table — a monitored +snapshot of your tenant's flows enriched with governance metadata and run statistics. + +| Tool | What it does | +|---|---| +| `list_store_flows` | Search flows from the cache with governance flags, run failure rates, and owner metadata | +| `get_store_flow` | Get full cached details for a single flow including run stats and governance fields | +| `get_store_flow_trigger_url` | Get the trigger URL from the cache (instant, no PA API call) | +| `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_summary` | Aggregated stats: success rate, failure count, avg/max duration | +| `set_store_flow_state` | Start or stop a flow via the PA API and sync the result back to the store | +| `update_store_flow` | Update governance metadata (description, tags, monitor flag, notification rules, business impact) | +| `list_store_environments` | List all environments from the cache | +| `list_store_makers` | List all makers (citizen developers) from the cache | +| `get_store_maker` | Get a maker's flow/app counts and account status | +| `list_store_power_apps` | List all Power Apps canvas apps from the cache | +| `list_store_connections` | List all Power Platform connections from the cache | + +--- + +## Which Tool Tier to Call First + +| Task | Tool | Notes | +|---|---|---| +| List flows | `list_live_flows` | Always current — calls PA API directly | +| Read a definition | `get_live_flow` | Always fetched live — not cached | +| Debug a failure | `get_live_flow_runs` → `get_live_flow_run_error` | Use live run data | + +> ⚠️ **`list_live_flows` returns a direct array** — not a wrapper object. Iterate the result directly. + +> Store tools (`list_store_flows`, `get_store_flow`, etc.) are available to **FlowStudio for Teams** subscribers and provide cached governance metadata. Use live tools when in doubt — they work for all subscription tiers. + +--- + +## Step 0 — Discover Available Tools + +Always start by calling `tools/list` to confirm the server is reachable and see +exactly which tool names are available (names may vary by server version): + +```python +import json, urllib.request + +TOKEN = "" +MCP = "https://mcp.flowstudio.app/mcp" + +def mcp_raw(method, params=None, cid=1): + payload = {"jsonrpc": "2.0", "method": method, "id": cid} + if params: + payload["params"] = params + req = urllib.request.Request(MCP, data=json.dumps(payload).encode(), + headers={"x-api-key": TOKEN, "Content-Type": "application/json"}) + try: + resp = urllib.request.urlopen(req, timeout=30) + except urllib.error.HTTPError as e: + raise RuntimeError(f"MCP HTTP {e.code} — check token and endpoint") from e + return json.loads(resp.read()) + +raw = mcp_raw("tools/list") +if "error" in raw: + print("ERROR:", raw["error"]); raise SystemExit(1) +for t in raw["result"]["tools"]: + print(t["name"], "—", t["description"][:60]) +``` + +--- + +## Core MCP Helper (Python) + +Use this helper throughout all subsequent operations: + +```python +import json, urllib.request + +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": "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. + +--- + +## Core MCP Helper (Node.js) + +Equivalent helper for Node.js 18+ (built-in `fetch` — no packages required): + +```js +const 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": "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`. + +--- + +## List Flows + +```python +ENV = "Default-" + +flows = mcp("list_live_flows", {"environmentName": ENV}) +# Returns direct array: +# [{"id": "0757041a-...", "displayName": "My Flow", "state": "Started", +# "triggerType": "Request", "createdTime": "...", "owners": ""}, ...] +for f in flows: + FLOW_ID = f["id"] # plain UUID — use directly as flowName + print(FLOW_ID, "|", f["displayName"], "|", f["state"]) +``` + +--- + +## Read a Flow Definition + +```python +FLOW = "" + +flow = mcp("get_live_flow", {"environmentName": ENV, "flowName": FLOW}) + +# Display name and state +print(flow["properties"]["displayName"]) +print(flow["properties"]["state"]) + +# List all action names +actions = flow["properties"]["definition"]["actions"] +print("Actions:", list(actions.keys())) + +# Inspect one action's expression +print(actions["Compose_Filter"]["inputs"]) +``` + +--- + +## Check Run History + +```python +# Most recent runs (newest first) +runs = mcp("get_live_flow_runs", {"environmentName": ENV, "flowName": FLOW, "top": 5}) +# Returns direct array: +# [{"name": "08584296068667933411438594643CU15", +# "status": "Failed", +# "startTime": "2026-02-25T06:13:38.6910688Z", +# "endTime": "2026-02-25T06:15:24.1995008Z", +# "triggerName": "manual", +# "error": {"code": "ActionFailed", "message": "An action failed..."}}, +# {"name": "08584296028664130474944675379CU26", +# "status": "Succeeded", "error": null, ...}] + +for r in runs: + print(r["name"], r["status"]) + +# Get the name of the first failed run +run_id = next(r["name"] for r in runs if r["status"] == "Failed", None) +``` + +--- + +## Inspect an Action's Output + +```python +run_id = runs[0]["name"] + +out = mcp("get_live_flow_run_action_outputs", { + "environmentName": ENV, + "flowName": FLOW, + "runName": run_id, + "actionName": "Get_Customer_Record" # exact action name from the definition +}) +print(json.dumps(out, indent=2)) +``` + +--- + +## Get a Run's Error + +```python +err = mcp("get_live_flow_run_error", { + "environmentName": ENV, + "flowName": FLOW, + "runName": run_id +}) +# Returns: +# {"runName": "08584296068...", +# "failedActions": [ +# {"actionName": "HTTP_find_AD_User_by_Name", "status": "Failed", +# "code": "NotSpecified", "startTime": "...", "endTime": "..."}, +# {"actionName": "Scope_prepare_workers", "status": "Failed", +# "error": {"code": "ActionFailed", "message": "An action failed..."}} +# ], +# "allActions": [ +# {"actionName": "Apply_to_each", "status": "Skipped"}, +# {"actionName": "Compose_WeekEnd", "status": "Succeeded"}, +# ... +# ]} + +# The ROOT cause is usually the deepest entry in failedActions: +root = err["failedActions"][-1] +print(f"Root failure: {root['actionName']} → {root['code']}") +``` + +--- + +## Resubmit a Run + +```python +result = mcp("resubmit_live_flow_run", { + "environmentName": ENV, + "flowName": FLOW, + "runName": run_id +}) +print(result) # {"resubmitted": true, "triggerName": "..."} +``` + +--- + +## Cancel a Running Run + +```python +mcp("cancel_live_flow_run", { + "environmentName": ENV, + "flowName": FLOW, + "runName": run_id +}) +``` + +> ⚠️ **Do NOT cancel a run that shows `Running` because it is waiting for an +> adaptive card response.** That status is normal — the flow is paused waiting +> for a human to respond in Teams. Cancelling it will discard the pending card. + +--- + +## Full Round-Trip Example — Debug and Fix a Failing Flow + +```python +# ── 1. Find the flow ───────────────────────────────────────────────────── +flows = mcp("list_live_flows", {"environmentName": ENV}) +target = next(f for f in flows if "My Flow Name" in f["displayName"]) +FLOW_ID = target["id"] + +# ── 2. Get the most recent failed run ──────────────────────────────────── +runs = mcp("get_live_flow_runs", {"environmentName": ENV, "flowName": FLOW_ID, "top": 5}) +# [{"name": "08584296068...", "status": "Failed", ...}, ...] +RUN_ID = next(r["name"] for r in runs if r["status"] == "Failed") + +# ── 3. Get per-action failure breakdown ────────────────────────────────── +err = mcp("get_live_flow_run_error", {"environmentName": ENV, "flowName": FLOW_ID, "runName": RUN_ID}) +# {"failedActions": [{"actionName": "HTTP_find_AD_User_by_Name", "code": "NotSpecified",...}], ...} +root_action = err["failedActions"][-1]["actionName"] +print(f"Root failure: {root_action}") + +# ── 4. Read the definition and inspect the failing action's expression ─── +defn = mcp("get_live_flow", {"environmentName": ENV, "flowName": FLOW_ID}) +acts = defn["properties"]["definition"]["actions"] +print("Failing action inputs:", acts[root_action]["inputs"]) + +# ── 5. Inspect the prior action's output to find the null ──────────────── +out = mcp("get_live_flow_run_action_outputs", { + "environmentName": ENV, "flowName": FLOW_ID, + "runName": RUN_ID, "actionName": "Compose_Names" +}) +nulls = [x for x in out.get("body", []) if x.get("Name") is None] +print(f"{len(nulls)} records with null Name") + +# ── 6. Apply the fix ───────────────────────────────────────────────────── +acts[root_action]["inputs"]["parameters"]["searchName"] = \ + "@coalesce(item()?['Name'], '')" + +conn_refs = defn["properties"]["connectionReferences"] +result = mcp("update_live_flow", { + "environmentName": ENV, "flowName": FLOW_ID, + "definition": defn["properties"]["definition"], + "connectionReferences": conn_refs +}) +assert result.get("error") is None, f"Deploy failed: {result['error']}" +# ⚠️ error key is always present — only fail if it is NOT None + +# ── 7. Resubmit and verify ─────────────────────────────────────────────── +mcp("resubmit_live_flow_run", {"environmentName": ENV, "flowName": FLOW_ID, "runName": RUN_ID}) + +import time; time.sleep(30) +new_runs = mcp("get_live_flow_runs", {"environmentName": ENV, "flowName": FLOW_ID, "top": 1}) +print(new_runs[0]["status"]) # Succeeded = done +``` + +--- + +## Auth & Connection Notes + +| Field | Value | +|---|---| +| Auth header | `x-api-key: ` — **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-` (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 `tools/list`) +- [action-types.md](references/action-types.md) — Power Automate action type patterns +- [connection-references.md](references/connection-references.md) — connector reference guide + +--- + +## More Capabilities + +For **diagnosing failing flows** end-to-end → load the `power-automate-debug` skill. + +For **building and deploying new flows** → load the `power-automate-build` skill. diff --git a/skills/power-automate-mcp/references/MCP-BOOTSTRAP.md b/skills/power-automate-mcp/references/MCP-BOOTSTRAP.md new file mode 100644 index 000000000..7dc716056 --- /dev/null +++ b/skills/power-automate-mcp/references/MCP-BOOTSTRAP.md @@ -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: +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":"","arguments":{...}}} +``` + +## Response Shape + +``` +Success → {"result":{"content":[{"type":"text","text":""}]}} +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` diff --git a/skills/power-automate-mcp/references/action-types.md b/skills/power-automate-mcp/references/action-types.md new file mode 100644 index 000000000..42507ce79 --- /dev/null +++ b/skills/power-automate-mcp/references/action-types.md @@ -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 `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 | diff --git a/skills/power-automate-mcp/references/connection-references.md b/skills/power-automate-mcp/references/connection-references.md new file mode 100644 index 000000000..08e839842 --- /dev/null +++ b/skills/power-automate-mcp/references/connection-references.md @@ -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`. diff --git a/skills/power-automate-mcp/references/tool-reference.md b/skills/power-automate-mcp/references/tool-reference.md new file mode 100644 index 000000000..81d09b64c --- /dev/null +++ b/skills/power-automate-mcp/references/tool-reference.md @@ -0,0 +1,441 @@ +# 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"`. + +### `list_store_connections` + +Same connection data from cache. + +--- + +## Flow Discovery & Listing + +### `list_live_flows` + +Response: wrapper object with `flows` array. +```json +{ + "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": "", + "definitionAvailable": true + } + ], + "totalCount": 100, + "userScopedCount": 80, + "adminScopedCount": 20, + "userScopedError": null, + "adminScopedError": null +} +``` + +> Access via `result["flows"]`. `id` is a plain UUID --- use directly as `flowName`. + +### `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**: `envId.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": "envId.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": "", + "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": "envId.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": "", + "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"`. +> +> `responseStatus` + `responseBody` contain the flow's Response action output. +> AAD-authenticated triggers are handled automatically. + +--- + +## Flow State Management + +### `set_store_flow_state` + +Start or stop a flow. Pass `state: "Started"` or `state: "Stopped"`. + +--- + +## 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": "" +} +``` + +### `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`. + +### `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`. From 0962c4716ae330c0f484b8bc409437feec5453a2 Mon Sep 17 00:00:00 2001 From: Catherine Han Date: Fri, 6 Mar 2026 15:06:39 +1100 Subject: [PATCH 2/2] fix: rename skill & address review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename power-automate-mcp → flowstudio-power-automate-mcp - Fix list_live_flows docs: returns wrapper object {mode, flows, totalCount, error}, not direct array - Fix next() syntax: add parens for generator with default arg - Add User-Agent header to tools/list discovery example - Standardize User-Agent to FlowStudio-MCP/1.0 (required by Cloudflare) - Add environmentName note for list_live_connections (required despite schema) - Update list_live_flows response shape in tool-reference.md All response shapes verified against live MCP server. --- docs/README.skills.md | 1 + .../SKILL.md | 27 ++++++++++--------- .../references/MCP-BOOTSTRAP.md | 0 .../references/action-types.md | 0 .../references/connection-references.md | 0 .../references/tool-reference.md | 12 ++++++--- 6 files changed, 23 insertions(+), 17 deletions(-) rename skills/{power-automate-mcp => flowstudio-power-automate-mcp}/SKILL.md (95%) rename skills/{power-automate-mcp => flowstudio-power-automate-mcp}/references/MCP-BOOTSTRAP.md (100%) rename skills/{power-automate-mcp => flowstudio-power-automate-mcp}/references/action-types.md (100%) rename skills/{power-automate-mcp => flowstudio-power-automate-mcp}/references/connection-references.md (100%) rename skills/{power-automate-mcp => flowstudio-power-automate-mcp}/references/tool-reference.md (97%) diff --git a/docs/README.skills.md b/docs/README.skills.md index e90a64b73..c10ec8efc 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -111,6 +111,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to | [finalize-agent-prompt](../skills/finalize-agent-prompt/SKILL.md) | Finalize prompt file using the role of an AI agent to polish the prompt for the end user. | None | | [finnish-humanizer](../skills/finnish-humanizer/SKILL.md) | Detect and remove AI-generated markers from Finnish text, making it sound like a native Finnish speaker wrote it. Use when asked to "humanize", "naturalize", or "remove AI feel" from Finnish text, or when editing .md/.txt files containing Finnish content. Identifies 26 patterns (12 Finnish-specific + 14 universal) and 4 style markers. | `references/patterns.md` | | [first-ask](../skills/first-ask/SKILL.md) | Interactive, input-tool powered, task refinement workflow: interrogates scope, deliverables, constraints before carrying out the task; Requires the Joyride extension. | None | +| [flowstudio-power-automate-mcp](../skills/flowstudio-power-automate-mcp/SKILL.md) | Connect to and operate Power Automate cloud flows via a FlowStudio MCP server. Use when asked to: list flows, read a flow definition, check run history, inspect action outputs, resubmit a run, cancel a running flow, view connections, get a trigger URL, validate a definition, monitor flow health, or any task that requires talking to the Power Automate API through an MCP tool. Also use for Power Platform environment discovery and connection management. Requires a FlowStudio MCP subscription or compatible server — see https://mcp.flowstudio.app | `references/MCP-BOOTSTRAP.md`
`references/action-types.md`
`references/connection-references.md`
`references/tool-reference.md` | | [fluentui-blazor](../skills/fluentui-blazor/SKILL.md) | Guide for using the Microsoft Fluent UI Blazor component library (Microsoft.FluentUI.AspNetCore.Components NuGet package) in Blazor applications. Use this when the user is building a Blazor app with Fluent UI components, setting up the library, using FluentUI components like FluentButton, FluentDataGrid, FluentDialog, FluentToast, FluentNavMenu, FluentTextField, FluentSelect, FluentAutocomplete, FluentDesignTheme, or any component prefixed with "Fluent". Also use when troubleshooting missing providers, JS interop issues, or theming. | `references/DATAGRID.md`
`references/LAYOUT-AND-NAVIGATION.md`
`references/SETUP.md`
`references/THEMING.md` | | [folder-structure-blueprint-generator](../skills/folder-structure-blueprint-generator/SKILL.md) | Comprehensive technology-agnostic prompt for analyzing and documenting project folder structures. Auto-detects project types (.NET, Java, React, Angular, Python, Node.js, Flutter), generates detailed blueprints with visualization options, naming conventions, file placement patterns, and extension templates for maintaining consistent code organization across diverse technology stacks. | None | | [game-engine](../skills/game-engine/SKILL.md) | Expert skill for building web-based game engines and games using HTML5, Canvas, WebGL, and JavaScript. Use when asked to create games, build game engines, implement game physics, handle collision detection, set up game loops, manage sprites, add game controls, or work with 2D/3D rendering. Covers techniques for platformers, breakout-style games, maze games, tilemaps, audio, multiplayer via WebRTC, and publishing games. | `assets/2d-maze-game.md`
`assets/2d-platform-game.md`
`assets/gameBase-template-repo.md`
`assets/paddle-game-template.md`
`assets/simple-2d-engine.md`
`references/3d-web-games.md`
`references/algorithms.md`
`references/basics.md`
`references/game-control-mechanisms.md`
`references/game-engine-core-principles.md`
`references/game-publishing.md`
`references/techniques.md`
`references/terminology.md`
`references/web-apis.md` | diff --git a/skills/power-automate-mcp/SKILL.md b/skills/flowstudio-power-automate-mcp/SKILL.md similarity index 95% rename from skills/power-automate-mcp/SKILL.md rename to skills/flowstudio-power-automate-mcp/SKILL.md index 15afdebcf..7866ed272 100644 --- a/skills/power-automate-mcp/SKILL.md +++ b/skills/flowstudio-power-automate-mcp/SKILL.md @@ -1,5 +1,5 @@ --- -name: power-automate-mcp +name: flowstudio-power-automate-mcp description: >- Connect to and operate Power Automate cloud flows via a FlowStudio MCP server. Use when asked to: list flows, read a flow definition, check run history, inspect @@ -120,7 +120,7 @@ snapshot of your tenant's flows enriched with governance metadata and run statis | Read a definition | `get_live_flow` | Always fetched live — not cached | | Debug a failure | `get_live_flow_runs` → `get_live_flow_run_error` | Use live run data | -> ⚠️ **`list_live_flows` returns a direct array** — not a wrapper object. Iterate the result directly. +> ⚠️ **`list_live_flows` returns a wrapper object** with a `flows` array — access via `result["flows"]`. > Store tools (`list_store_flows`, `get_store_flow`, etc.) are available to **FlowStudio for Teams** subscribers and provide cached governance metadata. Use live tools when in doubt — they work for all subscription tiers. @@ -142,7 +142,8 @@ def mcp_raw(method, params=None, cid=1): if params: payload["params"] = params req = urllib.request.Request(MCP, data=json.dumps(payload).encode(), - headers={"x-api-key": TOKEN, "Content-Type": "application/json"}) + headers={"x-api-key": TOKEN, "Content-Type": "application/json", + "User-Agent": "FlowStudio-MCP/1.0"}) try: resp = urllib.request.urlopen(req, timeout=30) except urllib.error.HTTPError as e: @@ -173,7 +174,7 @@ def mcp(tool, args, cid=1): "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": "MCP/1.0"}) + "User-Agent": "FlowStudio-MCP/1.0"}) try: resp = urllib.request.urlopen(req, timeout=120) except urllib.error.HTTPError as e: @@ -213,7 +214,7 @@ async function mcp(tool, args, cid = 1) { headers: { "x-api-key": TOKEN, "Content-Type": "application/json", - "User-Agent": "MCP/1.0", + "User-Agent": "FlowStudio-MCP/1.0", }, body: JSON.stringify(payload), }); @@ -237,11 +238,11 @@ async function mcp(tool, args, cid = 1) { ```python ENV = "Default-" -flows = mcp("list_live_flows", {"environmentName": ENV}) -# Returns direct array: -# [{"id": "0757041a-...", "displayName": "My Flow", "state": "Started", -# "triggerType": "Request", "createdTime": "...", "owners": ""}, ...] -for f in flows: +result = mcp("list_live_flows", {"environmentName": ENV}) +# Returns wrapper object: +# {"mode": "owner", "flows": [{"id": "0757041a-...", "displayName": "My Flow", +# "state": "Started", "triggerType": "Request", ...}], "totalCount": 42, "error": null} +for f in result["flows"]: FLOW_ID = f["id"] # plain UUID — use directly as flowName print(FLOW_ID, "|", f["displayName"], "|", f["state"]) ``` @@ -288,7 +289,7 @@ for r in runs: print(r["name"], r["status"]) # Get the name of the first failed run -run_id = next(r["name"] for r in runs if r["status"] == "Failed", None) +run_id = next((r["name"] for r in runs if r["status"] == "Failed"), None) ``` --- @@ -371,8 +372,8 @@ mcp("cancel_live_flow_run", { ```python # ── 1. Find the flow ───────────────────────────────────────────────────── -flows = mcp("list_live_flows", {"environmentName": ENV}) -target = next(f for f in flows if "My Flow Name" in f["displayName"]) +result = mcp("list_live_flows", {"environmentName": ENV}) +target = next(f for f in result["flows"] if "My Flow Name" in f["displayName"]) FLOW_ID = target["id"] # ── 2. Get the most recent failed run ──────────────────────────────────── diff --git a/skills/power-automate-mcp/references/MCP-BOOTSTRAP.md b/skills/flowstudio-power-automate-mcp/references/MCP-BOOTSTRAP.md similarity index 100% rename from skills/power-automate-mcp/references/MCP-BOOTSTRAP.md rename to skills/flowstudio-power-automate-mcp/references/MCP-BOOTSTRAP.md diff --git a/skills/power-automate-mcp/references/action-types.md b/skills/flowstudio-power-automate-mcp/references/action-types.md similarity index 100% rename from skills/power-automate-mcp/references/action-types.md rename to skills/flowstudio-power-automate-mcp/references/action-types.md diff --git a/skills/power-automate-mcp/references/connection-references.md b/skills/flowstudio-power-automate-mcp/references/connection-references.md similarity index 100% rename from skills/power-automate-mcp/references/connection-references.md rename to skills/flowstudio-power-automate-mcp/references/connection-references.md diff --git a/skills/power-automate-mcp/references/tool-reference.md b/skills/flowstudio-power-automate-mcp/references/tool-reference.md similarity index 97% rename from skills/power-automate-mcp/references/tool-reference.md rename to skills/flowstudio-power-automate-mcp/references/tool-reference.md index 81d09b64c..b447a9c0d 100644 --- a/skills/power-automate-mcp/references/tool-reference.md +++ b/skills/flowstudio-power-automate-mcp/references/tool-reference.md @@ -79,6 +79,10 @@ Response: wrapper object with `connections` array. > `"/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` @@ -93,6 +97,7 @@ Same connection data from cache. Response: wrapper object with `flows` array. ```json { + "mode": "owner", "flows": [ { "id": "0757041a-8ef2-cf74-ef06-06881916f371", @@ -107,14 +112,13 @@ Response: wrapper object with `flows` array. } ], "totalCount": 100, - "userScopedCount": 80, - "adminScopedCount": 20, - "userScopedError": null, - "adminScopedError": null + "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`