flowstudio-power-automate-debug について
FlowStudio MCP を使って Power Automate のクラウドフローの失敗を調べる診断スキルです。エージェントが実行エラーからアクションの入出力をたどって原因を特定し、修正を適用して実行を再送信し、検証します。
主な機能
- 01フローと失敗した実行の特定
- 02エラーとアクション出力の確認
- 03上流アクションをたどるデータ追跡
- 04式と接続の問題の診断
- 05修正の適用と実行の再送信
活用シーン
- 01失敗したフロー実行の調査
- 02空値や誤った入力データの特定
- 03HTTP アクション障害の確認
- 04過去の実行による修正の検証
MCP 対応
FlowStudio MCP ツールでフローと実行履歴を検索し、エラー詳細やアクション出力を調べ、フローを更新して実行を再送信します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ github/ awesome-copilot --skill flowstudio-power-automate-debugインストール後、Claude Code で/flowstudio-power-automate-debugを入力して読み込まれたか確認します。
同梱ファイルreferences/debug-workflow.mdreferences/common-errors.md
詳細
FlowStudio MCP による Power Automate のデバッグ
FlowStudio MCP サーバーを使用して、失敗した Power Automate クラウドフローを調査するための手順を順を追って説明します。
実際のデバッグ例:子フローの式エラー | フローのバグではなくデータ入力の問題 | null 値による子フローのクラッシュ
前提条件:有効な JWT を使用して FlowStudio MCP サーバーに接続できる必要があります。
接続の設定については、flowstudio-power-automate-mcp スキルを参照してください。
https://mcp.flowstudio.app でサブスクライブしてください
信頼できる情報源
まず必ず
list_skills/tool_searchを呼び出し、利用可能なツール名とパラメータスキーマを確認してください。ツール名とパラメータはサーバーのバージョンによって変更される場合があります。 このスキルでは、ツールスキーマからは分からないレスポンスの形式、動作に関する注意事項、診断パターンを説明します。このドキュメントの内容がtool_searchまたは実際の API レスポンスと異なる場合は、API の情報を優先してください。
Python ヘルパー
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
ステップ 1 — フローを特定する
result = mcp("list_live_flows", environmentName=ENV)
# Returns a wrapper object: {mode, flows, totalCount, error}
target = next(f for f in result["flows"] if "My Flow Name" in f["displayName"])
FLOW_ID = target["id"] # plain UUID — use directly as flowName
print(FLOW_ID)
ステップ 2 — 失敗した実行を見つける
runs = mcp("get_live_flow_runs", environmentName=ENV, flowName=FLOW_ID, top=5)
# Returns direct array (newest first):
# [{"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": "...", "status": "Succeeded", "error": null, ...}]
for r in runs:
print(r["name"], r["status"], r["startTime"])
RUN_ID = next(r["name"] for r in runs if r["status"] == "Failed")
ステップ 3 — 最上位のエラーを取得する
重要:
get_live_flow_run_errorは失敗したアクションがどれかを示します。get_live_flow_run_action_outputsは失敗した理由を示します。両方を呼び出す必要があります。 エラーだけで調査を終わらせないでください。ActionFailed、NotSpecified、InternalServerErrorなどのエラーコードは一般的なラッパーにすぎません。実際の根本原因(誤ったフィールド、null 値、HTTP 500 の本文、スタックトレース)は、アクションの入力と出力でのみ確認できます。
err = mcp("get_live_flow_run_error",
environmentName=ENV, flowName=FLOW_ID, runName=RUN_ID)
# Returns:
# {
# "runName": "08584296068667933411438594643CU15",
# "failedActions": [
# {"actionName": "Apply_to_each_prepare_workers", "status": "Failed",
# "error": {"code": "ActionFailed", "message": "An action failed..."},
# "startTime": "...", "endTime": "..."},
# {"actionName": "HTTP_find_AD_User_by_Name", "status": "Failed",
# "code": "NotSpecified", "startTime": "...", "endTime": "..."}
# ],
# "allActions": [
# {"actionName": "Apply_to_each", "status": "Skipped"},
# {"actionName": "Compose_WeekEnd", "status": "Succeeded"},
# ...
# ]
# }
# failedActions is ordered outer-to-inner. The ROOT cause is the LAST entry:
root = err["failedActions"][-1]
print(f"Root action: {root['actionName']} → code: {root.get('code')}")
# allActions shows every action's status — useful for spotting what was Skipped
# See common-errors.md to decode the error code.
ステップ 4 — 失敗したアクションの入力と出力を確認する
これは最も重要なステップです。
get_live_flow_run_errorから分かるのは一般的なエラーコードだけです。実際のエラーの詳細(HTTP ステータスコード、レスポンス本文、スタックトレース、null 値)は、アクションの実行時の入力と出力に含まれています。失敗したアクションを特定したら、すぐに必ず確認してください。
# Get the root failing action's full inputs and outputs
root_action = err["failedActions"][-1]["actionName"]
detail = mcp("get_live_flow_run_action_outputs",
environmentName=ENV,
flowName=FLOW_ID,
runName=RUN_ID,
actionName=root_action)
if len(detail) > 1:
print(f"{root_action} returned {len(detail)} repetitions; inspect iteration indexes")
out = detail[0] if detail else {}
print(f"Action: {out.get('actionName')}")
print(f"Status: {out.get('status')}")
# For HTTP actions, the real error is in outputs.body
if isinstance(out.get("outputs"), dict):
status_code = out["outputs"].get("statusCode")
body = out["outputs"].get("body", {})
print(f"HTTP {status_code}")
print(json.dumps(body, indent=2)[:500])
# Error bodies are often nested JSON strings — parse them
if isinstance(body, dict) and "error" in body:
err_detail = body["error"]
if isinstance(err_detail, str):
err_detail = json.loads(err_detail)
print(f"Error: {err_detail.get('message', err_detail)}")
# For expression errors, the error is in the error field
if out.get("error"):
print(f"Error: {out['error']}")
# Also check inputs — they show what expression/URL/body was used
if out.get("inputs"):
print(f"Inputs: {json.dumps(out['inputs'], indent=2)[:500]}")
アクションの出力から分かること(エラーコードだけでは分からないこと)
get_live_flow_run_error のエラーコード | get_live_flow_run_action_outputs で分かること |
|---|---|
ActionFailed | 実際に失敗したネストされたアクションと、その HTTP レスポンス |
NotSpecified | 実際のエラーを含む HTTP ステータスコードとレスポンス本文 |
InternalServerError | サーバーのエラーメッセージ、スタックトレース、または API エラーの JSON |
InvalidTemplate | 失敗した正確な式と、null 値または型が誤った値 |
BadRequest | 送信されたリクエスト本文と、サーバーが拒否した理由 |
Foreach の反復
actionName が foreach 内のアクションを指している場合、出力ツールはそのアクションのすべての反復を返すことがあります。各項目には、ループ名とゼロベースの itemIndex を含む repetitionIndexes が含まれる場合があります。疑わしい項目を見つけたら、iterationIndex を使って該当する反復を確認します。
all_reps = mcp("get_live_flow_run_action_outputs",
environmentName=ENV,
flowName=FLOW_ID,
runName=RUN_ID,
actionName=root_action)
for rep in all_reps[:10]:
print(rep.get("repetitionIndexes"), rep.get("status"), rep.get("error"))
one_rep = mcp("get_live_flow_run_action_outputs",
environmentName=ENV,
flowName=FLOW_ID,
runName=RUN_ID,
actionName=root_action,
iterationIndex=3)
証拠用 Compose の前後配置
コネクタの動作に不確実な点がある場合は、リスクのあるアクションの前に Compose_*_Request を追加し、その後に Compose_*_Result を追加します。結果アクションは Succeeded と Failed の両方で実行されるようにします。これにより、再デプロイしなくても、今後のデバッグでペイロードを明確に確認できます。これらの前後配置には、シークレットや長いバイナリペイロードを含めないでください。
例:HTTP アクションが 500 を返す場合
Error code: "InternalServerError" ← this tells you nothing
Action outputs reveal:
HTTP 500
body: {"error": "Cannot read properties of undefined (reading 'toLowerCase')
at getClientParamsFromConnectionString (storage.js:20)"}
← THIS tells you the Azure Function crashed because a connection string is undefined
例:null による式エラー
Error code: "BadRequest" ← generic
Action outputs reveal:
inputs: "body('HTTP_GetTokenFromStore')?['token']?['access_token']"
outputs: "" ← empty string, the path resolved to null
← THIS tells you the response shape changed — token is at body.access_token, not body.token.access_token
ステップ 5 — フロー定義を読む
defn = mcp("get_live_flow", environmentName=ENV, flowName=FLOW_ID)
actions = defn["properties"]["definition"]["actions"]
print(list(actions.keys()))
定義内で失敗したアクションを見つけます。そのアクションの inputs 式を確認し、どのようなデータを想定しているかを把握します。
ステップ 6 — 失敗箇所からさかのぼる
失敗したアクションの入力が上流のアクションを参照している場合は、 それらも調べます。問題のあるデータの発生元が見つかるまで、チェーンを さかのぼってください。
# Inspect multiple actions leading up to the failure
for action_name in [root_action, "Compose_WeekEnd", "HTTP_Get_Data"]:
result = mcp("get_live_flow_run_action_outputs",
environmentName=ENV,
flowName=FLOW_ID,
runName=RUN_ID,
actionName=action_name)
out = result[0] if result else {}
print(f"\n--- {action_name} ({out.get('status')}) ---")
print(f"Inputs: {json.dumps(out.get('inputs', ''), indent=2)[:300]}")
print(f"Outputs: {json.dumps(out.get('outputs', ''), indent=2)[:300]}")
⚠️ 配列を処理するアクションの出力ペイロードは、非常に大きくなることがあります。 出力する前に、必ずスライスしてください(例:
[:500])。
ヒント:問題のあるデータを生成したアクションが分からない場合は、
actionNameを省略すると、トップレベルのアクションが一覧表示されます。foreach 内のアクションを選んだら、iterationIndexを指定して、すべての反復をコンテキストに読み込まないようにしてください。
ステップ 7 — 根本原因を特定する
式のエラー(例:null に対する split)
エラーに InvalidTemplate または関数名が含まれている場合:
- 定義内で該当するアクションを見つけます
- そのアクションが読み取る上流のアクションまたは式を確認します
- その上流アクションの出力に null やフィールドの欠落がないか調べます
# Example: action uses split(item()?['Name'], ' ')
# → null Name in the source data
result = mcp("get_live_flow_run_action_outputs", ..., actionName="Compose_Names")
if not result:
print("No outputs returned for Compose_Names")
names = []
else:
names = result[0].get("outputs", {}).get("body") or []
nulls = [x for x in names if x.get("Name") is None]
print(f"{len(nulls)} records with null Name")
フィールドパスの誤り
式 triggerBody()?['fieldName'] が null を返す場合、fieldName が誤っています。
トリガーの出力を調べて、実際のフィールド名を確認してください:
result = mcp("get_live_flow_run_action_outputs", ..., actionName="<trigger-action-name>")
print(json.dumps(result[0].get("outputs"), indent=2)[:500])
エラーを返す HTTP アクション
エラーコードが InternalServerError または NotSpecified の場合は、実際の HTTP ステータスとレスポンス本文を確認するために、必ずアクションの出力を調べてください:
result = mcp("get_live_flow_run_action_outputs", ..., actionName="HTTP_Get_Data")
out = result[0]
print(f"HTTP {out['outputs']['statusCode']}")
print(json.dumps(out['outputs']['body'], indent=2)[:500])
接続/認証の失敗
ConnectionAuthorizationFailed がないか確認してください。接続の所有者は、フローの実行に使われているサービスアカウントと一致する必要があります。API 経由では修正できません。PA デザイナーで修正してください。
Outlook のユーザー選択失敗(DynamicListValuesUndefinedOrInvalid)
GetEmailsV3 などの Outlook アクションでは、mailboxAddress、to、cc、from といったパラメーターのドロップダウンが builtInOperation:AadGraph.GetUsers によって提供されます。しかし、この操作は PA の listEnum レイヤーで壊れており、常に DynamicListValuesUndefinedOrInvalid を返します。エージェントが update_live_flow 経由で Outlook アクションを再構築または変更し、動的なオプションからユーザーを解決しようとすると、この問題が発生します。AadGraph を再試行して解決しようとしないでください。代わりに shared_office365users.SearchUserV2 に切り替えてください(同じ AAD ユーザー形式が返されます)。describe_live_connector を使って、該当するパラメーターに構造化された fallback があるかどうかを確認し、壊れている AadGraph 操作ではなく shared_office365users.SearchUserV2 に対して get_live_dynamic_options を呼び出してください。ドロップダウンのオプションではなく動的なフィールドスキーマを取得する場合は、describe_live_connector が返すメタデータを使って get_live_dynamic_properties を呼び出してください。
ステップ 8 — 修正を適用する
式/データの問題の場合:
defn = mcp("get_live_flow", environmentName=ENV, flowName=FLOW_ID)
acts = defn["properties"]["definition"]["actions"]
# Example: fix split on potentially-null Name
acts["Compose_Names"]["inputs"] = \
"@coalesce(item()?['Name'], 'Unknown')"
conn_refs = defn["properties"]["connectionReferences"]
result = mcp("update_live_flow",
environmentName=ENV,
flowName=FLOW_ID,
definition=defn["properties"]["definition"],
connectionReferences=conn_refs)
print(result.get("error")) # None = success
⚠️
update_live_flowは常にerrorキーを返します。 値がnull(Python のNone)の場合は成功です。
ステップ 9 — 修正を検証する
HTTP トリガーに限らず、どのフローのテストにも
resubmit_live_flow_runを使ってください。resubmit_live_flow_runは、以前の実行を元のトリガーペイロードで再生します。これは、Recurrence、SharePoint の「アイテムが作成されたとき」、コネクタの Webhook、Button トリガー、HTTP トリガーなど、すべてのトリガーの種類で機能します。ユーザーに手動でフローをトリガーするよう依頼したり、次のスケジュール実行を待ったりする必要はありません。
resubmitを利用できないのは、一度も実行されていない新規フローだけです。再生できる過去の実行がありません。
# Resubmit the failed run — works for ANY trigger type
resubmit = mcp("resubmit_live_flow_run",
environmentName=ENV, flowName=FLOW_ID, runName=RUN_ID)
print(resubmit) # {"resubmitted": true, "triggerName": "..."}
# Wait ~30 s then check
import time; time.sleep(30)
new_runs = mcp("get_live_flow_runs", environmentName=ENV, flowName=FLOW_ID, top=3)
print(new_runs[0]["status"]) # Succeeded = done
resubmit と trigger の使い分け
| シナリオ | 使用するもの | 理由 |
|---|---|---|
| どのフローでも修正をテストする場合 | resubmit_live_flow_run | 失敗の原因となったトリガーペイロードをそのまま再生するため、検証に最適です |
| Recurrence/スケジュールされたフロー | trigger_live_flow(body なし) | ポータルの「フローを実行」ボタンのように、今すぐ実行します。resubmit は過去の実行データを再生します |
| SharePoint/コネクタのトリガー | resubmit_live_flow_run | 実際の SP アイテムを作成せずにトリガーすることはできません |
| 独自のテストペイロードを使う HTTP、Button、または PowerApps トリガー | trigger_live_flow | 元の実行とは異なるデータを送信する必要がある場合に使用します |
| 一度も実行されていない新規フロー | trigger_live_flow | resubmit できる過去の実行がありません |
カスタムペイロードを使用した HTTP、Button、PowerApps フローのテスト
Request トリガー(HTTP リクエスト、手動の Button、または PowerApps)を使用するフローで、元の実行とは異なるペイロードを送信する必要がある場合は、trigger_live_flow を使用します。どの種類でも、トリガーの入力は body として渡します。
# First inspect what the trigger expects — read directly from the flow definition
defn = mcp("get_live_flow", environmentName=ENV, flowName=FLOW_ID)
triggers = defn["properties"]["definition"]["triggers"]
manual = next(iter(triggers.values())) # usually the only trigger on HTTP flows
request_schema = manual.get("inputs", {}).get("schema")
print("Expected body schema:", request_schema)
# Response schemas live on Response action(s) in the actions block
for name, act in defn["properties"]["definition"]["actions"].items():
if act.get("type") == "Response":
print(f"Response {name}:", act.get("inputs", {}).get("schema"))
# Trigger with a test payload
result = mcp("trigger_live_flow",
environmentName=ENV,
flowName=FLOW_ID,
body={"name": "Test User", "value": 42})
print(f"Status: {result['responseStatus']}, Body: {result.get('responseBody')}")
print(f"Kind: {result['triggerKind']}, via: {result['invocation']}, run: {result.get('runName')}")
if result.get("warning"):
print(result["warning"]) # required trigger inputs you left out
trigger_live_flowは、AAD 認証を使用するトリガーを自動的に処理します。Requestトリガー(HTTP リクエスト、Button、PowerApps)と、スケジュール済み(Recurrence)フローに対応しています。スケジュール済みフローは直ちに実行されます。スケジュール済みトリガーは入力を受け取らないため、bodyは不要です(指定すると拒否されます)。 自動化されたコネクタートリガーは、ソースイベントからのみ起動します。Power Automate は、トリガーの
required入力を強制しません。入力を省略しても実行は開始されますが、その入力は null になり、結果には不足しているキーを示すwarningが含まれます。それが問題になる場合は、実行をキャンセルして、完全な body を指定して再度呼び出してください。
runNameが返されるのは、Button と PowerApps の実行のみです。HTTP トリガーの場合は、get_live_flow_runsで実行を探してください。ブラウザー拡張機能のキーを使用する場合、Button と PowerApps のトリガーは空の body でのみ実行されます。ツールはその旨を示し、回避策を列挙します。過去の実行を再送信する、
coalesce(triggerBody()?['x'], 'value')を使用してフロー内で入力のデフォルト値を設定する、または標準の API キーを使用する方法があります。
クイックリファレンス:診断の判断ツリー
| 症状 | 最初に使うツール | 次に必ず呼び出すツール | 確認する内容 |
|---|---|---|---|
| フローの状態が「Failed」になる | get_live_flow_run_error | 失敗したアクションに対して get_live_flow_run_action_outputs | outputs 内の HTTP ステータスとレスポンス本文 |
エラーコードが汎用的(ActionFailed、NotSpecified) | — | get_live_flow_run_action_outputs | outputs.body に実際のエラーメッセージ、スタックトレース、または API エラーが含まれている |
| HTTP アクションが 500 を返す | — | get_live_flow_run_action_outputs | サーバーエラーの詳細を含む outputs.statusCode と outputs.body |
| 式のクラッシュ | — | 直前のアクションに対して get_live_flow_run_action_outputs | 出力本文内の null フィールドまたは型の異なるフィールド |
| フローが開始しない | get_live_flow | — | properties.state = "Started" であることを確認 |
| アクションが誤ったデータを返す | get_live_flow_run_action_outputs | — | 実際の出力本文と期待される出力を比較 |
| 修正を適用しても失敗する | 再送信後に get_live_flow_runs | — | 新しい実行の status フィールド |
ルール:エラーコードだけで診断してはいけません。
get_live_flow_run_errorは失敗したアクションを特定します。get_live_flow_run_action_outputsは 実際の原因を明らかにします。必ず両方を呼び出してください。
リファレンスファイル
- common-errors.md — エラーコード、考えられる原因、修正方法
- debug-workflow.md — 複雑な障害に対応する詳細な判断ツリー
関連スキル
flowstudio-power-automate-mcp— 基礎スキル:接続の設定、MCP ヘルパー、ツールの検出flowstudio-power-automate-build— 新しいフローの構築とデプロイ