跳到主要内容
知仓学习社ZHICANG

flowstudio-power-automate-build

>-

不碰外部(只输出文字)无严重或高危命中github/awesome-copilot

它会碰到什么

扫了多少7 个文本文件,85 KB
它会碰到什么不碰外部(只输出文字)
命中总数4 处
命中统计严重 0 · 高 0 · 中 0 · 低 0

这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。

技能内容

Build & Deploy Power Automate Flows with FlowStudio MCP

Step-by-step guide for constructing and deploying Power Automate cloud flows

programmatically through the FlowStudio MCP server.

Prerequisite: A FlowStudio MCP server must be reachable with a valid JWT.

See the flowstudio-power-automate-mcp skill for connection setup.

Subscribe at https://mcp.flowstudio.app

Workflow:

  1. Load current build tools.
  2. Check for an existing flow.
  3. Resolve connection references.
  4. Build the definition.
  5. Deploy.
  6. Verify.
  7. Test.

Source of Truth

> Always call list_skills / tool_search first to confirm available tool

> names and parameter schemas. Tool names and parameters may change between

> server versions.

> This skill covers response shapes, behavioral notes, and build patterns —

> things tool schemas cannot tell you. If this document disagrees with

> tool_search or a real API response, the API wins.


Python Helper

import json, urllib.request

MCP_URL   = "https://mcp.flowstudio.app/mcp"
MCP_TOKEN = "<YOUR_JWT_TOKEN>"

def mcp(tool, **kwargs):
    payload = json.dumps({"jsonrpc": "2.0", "id": 1, "method": "tools/call",
                          "params": {"name": tool, "arguments": kwargs}}).encode()
    req = urllib.request.Request(MCP_URL, data=payload,
        headers={"x-api-key": MCP_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'])}")
    return json.loads(raw["result"]["content"][0]["text"])

ENV = "<environment-id>"  # e.g. Default-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

0. Load the Current Build Tools

For a brand-new flow, load the server's create-flow bundle. For editing an

existing flow, load build-flow. This keeps the agent aligned with the MCP

server's current schema before constructing JSON.

schemas = mcp("tool_search", query="skill:create-flow")
# Includes list_live_environments, list_live_connections,
# describe_live_connector, get_live_dynamic_options, update_live_flow.

If you need a tool outside the bundle, load it explicitly:

mcp("tool_search", query="select:get_live_dynamic_properties")

1. Safety Check: Does the Flow Already Exist?

Always look before you build to avoid duplicates:

results = mcp("list_live_flows",
    environmentName=ENV,
    mode="owner",
    search="My New Flow",
    top=20)

# list_live_flows returns { "flows": [...], "mode": "...", ... }
matches = [f for f in results["flows"]
           if "My New Flow".lower() in f["displayName"].lower()]

if len(matches) > 0:
    # Flow exists — modify rather than create
    FLOW_ID = matches[0]["id"]   # plain UUID from list_live_flows
    print(f"Existing flow: {FLOW_ID}")
    defn = mcp("get_live_flow", environmentName=ENV, flowName=FLOW_ID)
else:
    print("Flow not found — building from scratch")
    FLOW_ID = None

For very large environments, list_live_flows may return a continuation URL.

Pass it back as continuationUrl with the same mode to retrieve the next

batch. Use mode="admin" only when the user needs all environment flows and

the MCP identity has admin rights.


2. Obtain Connection References

Every connector action needs a connectionName that points to a key in the

flow's connectionReferences map. That key links to an authenticated connection

in the environment.

> MANDATORY: You MUST call list_live_connections first — do NOT ask the

> user for connection names or GUIDs. The API returns the exact values you need.

> Only prompt the user if the API confirms that required connections are missing.

2a — Find active connections

conns = mcp("list_live_connections", environmentName=ENV)
active = [c for c in conns["connections"]
          if c["statuses"][0]["status"] == "Connected"]
conn_map = {c["connectorName"]: c["id"] for c in active}

For a known connector, pass search to reduce output and get paste-ready

connectionReferenceTemplate and hostTemplate values:

sp_conns = mcp("list_live_connections",
    environmentName=ENV,
    search="shared_sharepointonline")

2b — Determine which connectors the flow needs

Common connector API names: SharePoint shared_sharepointonline, Outlook

shared_office365, Teams shared_teams, Approvals shared_approvals,

OneDrive shared_onedriveforbusiness, Excel shared_excelonlinebusiness,

Dataverse shared_commondataserviceforapps, Forms shared_microsoftforms.

Flows that need no connectors, such as Recurrence + Compose + HTTP only, can

omit connectionReferences.

2c — If connections are missing, guide the user

connectors_needed = ["shared_sharepointonline", "shared_office365"]  # adjust per flow
missing = [c for c in connectors_needed if c not in conn_map]
if missing:
    # STOP: connections require browser OAuth consent.
    # Ask the user to create the missing connector connections in the
    # selected environment, then re-run list_live_connections.
    raise Exception(f"Missing active connections: {missing}")

2d — Build the connectionReferences block

connection_references = {}
host_templates = {}
for connector in connectors_needed:
    c = next(c for c in active if c["connectorName"] == connector)
    connection_references[connector] = c.get("connectionReferenceTemplate") or {
        "connectionName": c["id"],   # the connection id from list_live_connections
        "source": "Invoker",
        "id": f"/providers/Microsoft.PowerApps/apis/{connector}"
    }
    host_templates[connector] = c.get("hostTemplate") or {
        "connectionName": connector
    }

In Step 3 action JSON, inputs.host.connectionName must be the map key such as

shared_teams, not the GUID. The GUID belongs only inside the

connectionReferences[connector].connectionName value. If an existing flow uses

the same connectors, you may also copy its properties.connectionReferences

from get_live_flow.


3. Build the Flow Definition

Construct the definition object. See [flow-schema.md](references/flow-schema.md)

for the full schema and these action pattern references for copy-paste templates:

  • [action-patterns-core.md](references/action-patterns-core.md) — Variables, control flow, expressions
  • [action-patterns-data.md](references/action-patterns-data.md) — Array transforms, HTTP, parsing
  • [action-patterns-connectors.md](references/action-patterns-connectors.md) — SharePoint, Outlook, Teams, Approvals
definition = {
    "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
    "contentVersion": "1.0.0.0",
    "triggers": { ... },   # see trigger-types.md / build-patterns.md
    "actions": { ... }     # see ACTION-PATTERNS-*.md / build-patterns.md
}

> See [build-patterns.md](references/build-patterns.md) for complete, ready-to-use

> flow definitions covering Recurrence+SharePoint+Teams, HTTP triggers, and more.

Discover connector operations before guessing JSON

For connector-backed triggers/actions, prefer the live connector describer over

hand-written shapes. It can return authored hints, canonical examples, variant

keys, inputs/outputs, and dynamic metadata pointers.

# Search across connectors when you know the user's intent but not the API.
matches = mcp("describe_live_connector",
    environmentName=ENV,
    search="send email",
    top=5)

# Describe a specific operation before copying an exampleDefinition.
op = mcp("describe_live_connector",
    environmentName=ENV,
    connectorName="shared_office365",
    operationId="SendEmailV2")
print(op.get("hint"))

When an operation has multiple authored variants, request the variant the flow

needs:

teams_chat = mcp("describe_live_connector",
    environmentName=ENV,
    connectorName="shared_teams",
    operationId="PostMessageToConversation",
    variant="flowbot_chat")

When the operation description says a parameter has dynamic options or dynamic

properties, call the indicated next tool:

sp_op = mcp("describe_live_connector",
    environmentName=ENV,
    connectorName="shared_sharepointonline",
    operationId="GetItems")

sites = mcp("get_live_dynamic_options",
    environmentName=ENV,
    connectorName="shared_sharepointonline",
    connectionName=conn_map["shared_sharepointonline"],
    operationId="GetItems",
    parameterName="dataset",
    dynamicMetadata=sp_op["dynamicParameters"]["dataset"])

fields = mcp("get_live_dynamic_properties",
    environmentName=ENV,
    connectorName="shared_sharepointonline",
    connectionName=conn_map["shared_sharepointonline"],
    operationId="GetItems",
    parameterName="item",
    parameters={"dataset": "<site-url>", "table": "<list-id>"},
    dynamicMetadata=sp_op["dynamicProperties"]["item"])

Use dynamic options for dropdown IDs such as SharePoint sites/lists and Teams

teams/channels. Use dynamic properties for schema/field shapes such as

SharePoint list item columns.


4. Deploy (Create or Update)

update_live_flow handles both creation and updates in a single tool.

Create a new flow (no existing flow)

Omit flowName — the server generates a new GUID and creates via PUT:

definition["description"] = "Weekly SharePoint → Teams notification flow, built by agent"

result = mcp("update_live_flow",
    environmentName=ENV,
    # flowName omitted → creates a new flow
    definition=definition,
    connectionReferences=connection_references,
    displayName="Overdue Invoice Notifications"
)

if result.get("error") is not None:
    print("Create failed:", result["error"])
else:
    # Capture the new flow ID for subsequent steps
    FLOW_ID = result["created"]
    print(f"✅ Flow created: {FLOW_ID}")

Update an existing flow

Provide flowName to PATCH:

definition["description"] = (
    "Updated by agent on " + __import__('datetime').datetime.utcnow().isoformat()
)

result = mcp("update_live_flow",
    environmentName=ENV,
    flowName=FLOW_ID,
    definition=definition,
    connectionReferences=connection_references,
    displayName="My Updated Flow"
)

if result.get("error") is not None:
    print("Update failed:", result["error"])
else:
    print("Update succeeded:", result)

> ⚠️ update_live_flow always returns an error key.

> null (Python None) means success — do not treat the presence of the key as failure.

>

> ⚠️ Flow description lives at definition["description"]. The current server

> appends #flowstudio-mcp for usage tracking. Do not pass a top-level

> description argument unless tool_search shows one in the active schema.

Common deployment errors

| Error message (contains) | Cause | Fix |

|---|---|---|

| missing from connectionReferences | An action's host.connectionName references a key that doesn't exist in the connectionReferences map | Ensure host.connectionName uses the key from connectionReferences (e.g. shared_teams), not the raw GUID |

| ConnectionAuthorizationFailed / 403 | The connection GUID belongs to another user or is not authorized | Re-run Step 2a and use a connection owned by the current x-api-key user |

| InvalidTemplate / InvalidDefinition | Syntax error in the definition JSON | Check runAfter chains, expression syntax, and action type spelling |

| ConnectionNotConfigured | A connector action exists but the connection GUID is invalid or expired | Re-check list_live_connections for a fresh GUID |


5. Verify the Deployment

check = mcp("get_live_flow", environmentName=ENV, flowName=FLOW_ID)

# Confirm state
print("State:", check["properties"]["state"])  # Should be "Started"
# If state is "Stopped", use set_live_flow_state — NOT update_live_flow
# mcp("set_live_flow_state", environmentName=ENV, flowName=FLOW_ID, state="Started")

# Confirm the action we added is there
acts = check["properties"]["definition"]["actions"]
print("Actions:", list(acts.keys()))

6. Test the Flow

> MANDATORY: Before triggering any test run, ask the user for confirmation.

> Running a flow has real side effects — it may send emails, post Teams messages,

> write to SharePoint, start approvals, or call external APIs. Explain what the

> flow will do and wait for explicit approval before calling trigger_live_flow

> or resubmit_live_flow_run.

Updated flows (have prior runs) — ANY trigger type

> Use resubmit_live_flow_run first. It works for EVERY trigger type —

> Recurrence, SharePoint, connector webhooks, Button, and HTTP. It replays

> the original trigger payload. Do NOT ask the user to manually trigger the

> flow or wait for the next scheduled run.

runs = mcp("get_live_flow_runs", environmentName=ENV, flowName=FLOW_ID, top=1)
if runs:
    # Works for Recurrence, SharePoint, connector triggers — not just HTTP
    result = mcp("resubmit_live_flow_run",
        environmentName=ENV, flowName=FLOW_ID, runName=runs[0]["name"])
    print(result)   # {"resubmitted": true, "triggerName": "..."}

HTTP, Button, and PowerApps flows — custom test payload

Only use trigger_live_flow when you need to send a different payload

than the original run. For verifying a fix, resubmit_live_flow_run is

better because it uses the exact data that caused the failure.

defn = mcp("get_live_flow", environmentName=ENV, flowName=FLOW_ID)
triggers = defn["properties"]["definition"]["triggers"]
manual = next(iter(triggers.values()))
print("Expected body:", manual.get("inputs", {}).get("schema"))

result = mcp("trigger_live_flow",
    environmentName=ENV, flowName=FLOW_ID,
    body={"name": "Test", "value": 1})
print(f"Status: {result['responseStatus']}, via: {result['invocation']}")
print(result.get("warning"))   # set when a required input was missing: the run still ran, with null

Brand-new non-HTTP flows

A brand-new Recurrence flow needs no workaround: deploy it, then run it

immediately with trigger_live_flow and no body — same as the portal's

"Run flow" button. A body is refused; scheduled triggers take no inputs.

A brand-new connector-triggered flow (SharePoint, webhooks) has no prior

runs and cannot fire without a real source event. Deploy with a temporary

HTTP trigger, test the actions, then swap to the production trigger:

production_trigger = definition["triggers"]
definition["triggers"] = {
    "manual": {"type": "Request", "kind": "Http", "inputs": {"schema": {}}}
}
result = mcp("update_live_flow", environmentName=ENV,
    flowName=FLOW_ID,       # omit if creating new
    definition=definition, connectionReferences=connection_references,
    displayName="Overdue Invoice Notifications")
FLOW_ID = FLOW_ID or result["flowName"]

mcp("trigger_live_flow", environmentName=ENV, flowName=FLOW_ID,
    body={"sample": "payload"})
runs = mcp("get_live_flow_runs", environmentName=ENV, flowName=FLOW_ID, top=1)
if runs[0]["status"] == "Failed":
    err = mcp("get_live_flow_run_error",
        environmentName=ENV, flowName=FLOW_ID, runName=runs[0]["name"])
    raise Exception(err["failedActions"][-1])

definition["triggers"] = production_trigger
mcp("update_live_flow", environmentName=ENV, flowName=FLOW_ID,
    definition=definition, connectionReferences=connection_references)

The trigger is only the entry point; testing through HTTP still exercises the

same actions. If actions use triggerBody() or triggerOutputs(), pass a

representative body shaped like the production trigger payload.


Gotchas

| Mistake | Consequence | Prevention |

|---|---|---|

| Missing connectionReferences in deploy | 400 "Supply connectionReferences" | Always call list_live_connections first |

| "operationOptions" missing on Foreach | Parallel execution, race conditions on writes | Always add "Sequential" |

| union(old_data, new_data) | Old values override new (first-wins) | Use union(new_data, old_data) |

| split() on potentially-null string | InvalidTemplate crash | Wrap with coalesce(field, '') |

| Checking result["error"] exists | Always present; true error is != null | Use result.get("error") is not None |

| Flow deployed but state is "Stopped" | Flow won't run on schedule | Call set_live_flow_state with state: "Started" — do not use update_live_flow for state changes |

| Teams "Chat with Flow bot" recipient as object | 400 GraphUserDetailNotFound | Use plain string with trailing semicolon (see below) |

| Copilot/Skills flow not in a solution | Copilot Studio may not discover it as an agent tool | After deploy, call add_live_flow_to_solution with the target solutionId |

| Button/Skills trigger used for MCP testing | Runs even when a required input is missing (null) | Pass inputs in trigger_live_flow body; on warning, cancel and retry with the full body |

| Connector action missing metadata.operationMetadataId | Designer/run-only UI can behave inconsistently | Preserve existing IDs; add stable GUIDs for new connector actions |

| Placeholder Excel scriptId | Dynamic validation fails at save time | Resolve the real Office Script ID before deploying |

| SharePoint PatchItem omits required fields | Save can fail even if the field is not changing | Echo unchanged required fields such as item/Title |

| Copilot Studio connector calls a draft agent | Connector invocation can fail or hit stale behavior | Publish the agent before testing/resubmitting the flow |

Teams PostMessageToConversation — Recipient Formats

The body/recipient parameter format depends on the location value:

| Location | body/recipient format | Example |

|---|---|---|

| Chat with Flow bot | Plain email string with trailing semicolon | "user@contoso.com;" |

| Channel | Object with groupId and channelId | {"groupId": "...", "channelId": "..."} |

> Common mistake: passing {"to": "user@contoso.com"} for "Chat with Flow bot"

> returns a 400 GraphUserDetailNotFound error. The API expects a plain string.


Reference Files

  • [flow-schema.md](references/flow-schema.md) — Full flow definition JSON schema
  • [trigger-types.md](references/trigger-types.md) — Trigger type templates
  • [action-patterns-core.md](references/action-patterns-core.md) — Variables, control flow, expressions
  • [action-patterns-data.md](references/action-patterns-data.md) — Array transforms, HTTP, parsing
  • [action-patterns-connectors.md](references/action-patterns-connectors.md) — SharePoint, Outlook, Teams, Approvals
  • [build-patterns.md](references/build-patterns.md) — Complete flow definition templates (Recurrence+SP+Teams, HTTP trigger)

Related Skills

  • flowstudio-power-automate-mcp — Core connection setup and tool reference
  • flowstudio-power-automate-debug — Debug failing flows after deployment

想直接用这个技能?

本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。