{
  "markdown": "# power-automate-mcp-server\n\n[![Node.js CI](https://github.com/sapientsai/power-automate-mcp-server/actions/workflows/node.js.yml/badge.svg)](https://github.com/sapientsai/power-automate-mcp-server/actions/workflows/node.js.yml)\n[![npm version](https://img.shields.io/npm/v/power-automate-mcp-server.svg)](https://www.npmjs.com/package/power-automate-mcp-server)\n[![npm downloads](https://img.shields.io/npm/dm/power-automate-mcp-server.svg)](https://www.npmjs.com/package/power-automate-mcp-server)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\nAn MCP server that lets agents **inspect, operate, and author Microsoft Power Automate cloud\nflows** from a CLI/agent context — list and inspect flows, debug runs, check connections and\nowners, and (when explicitly enabled) enable/disable flows, cancel/resubmit runs, manage\nowners, and **create/update/delete flows**.\n\nPrimarily a **management** surface — the Power Automate portal's visual designer remains the\nbetter place to author complex flow logic — but `create_flow`/`update_flow`/`delete_flow` are\nalso available (write-gated) for programmatic authoring. Built on\n[SomaMCP](https://github.com/sapientsai/SomaMCP) (telemetry, health/info/\ndashboard, error classification) over FastMCP.\n\n> ⚠️ **Unofficial API.** v1 targets `api.flow.microsoft.com` — the surface the Power Automate\n> portal itself uses. Microsoft labels it _\"isn't supported. Customers should instead use the\n> Dataverse Web APIs.\"_ It is stable in practice and, unlike Dataverse, sees **all** flows\n> (including personal \"My Flows\") and works on M365‑seeded entitlements (no Premium license).\n> Every tool's description carries this disclaimer. A supported Dataverse backend is stubbed\n> for the future (see [`src/backend/dataverse/README.md`](src/backend/dataverse/README.md)).\n\n## Quick start\n\n```bash\npnpm install\ncp .env.example .env          # set AZURE_CLIENT_ID (see \"App registration\" below)\npnpm build\npnpm dev:stdio                # local agent over stdio (device-code sign-in to stderr)\n```\n\nOn first use the server prints a device-code prompt to **stderr**; open\n`https://microsoft.com/devicelogin`, enter the code, and sign in. The token is cached\n(`TOKEN_CACHE_PATH`, mode 0600) and silently refreshed thereafter.\n\n### Add to an MCP client (stdio)\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"power-automate\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"power-automate-mcp-server\", \"--stdio\"],\n      \"env\": { \"AZURE_CLIENT_ID\": \"<your-app-registration-client-id>\" },\n    },\n  },\n}\n```\n\n**Developing on this repo?** It ships a project-scoped [`.mcp.json`](.mcp.json) (stdio, local\n`dist/bin.js`). After `pnpm build`, export `AZURE_CLIENT_ID` and open the repo in Claude Code —\nthe `power-automate` server loads automatically (complete the device-code sign-in once; the\ncached token is then reused).\n\n## App registration\n\nThis server ships **no** default client id — you register your own (one‑time):\n\n1. **Azure Portal → Microsoft Entra ID → App registrations → New registration.**\n2. Name it (e.g. `power-automate-mcp`). Supported account types: **multitenant** (or\n   single‑tenant if you'll only ever use one org).\n3. **Authentication → Add a platform → Mobile and desktop applications.** Add redirect URI\n   `http://localhost` (unused by device code, but required to register the platform). Set\n   **\"Allow public client flows\" = Yes**.\n4. **API permissions → Add a permission.** You need a **delegated** permission for the Power\n   Automate / _Microsoft Flow Service_ API. If it isn't in the picker, see \"Token audience\"\n   below — this is the known friction point.\n5. Copy the **Application (client) ID** → `AZURE_CLIENT_ID`.\n\nFor unattended `clientCredentials` mode instead: add a **client secret**, grant **application**\npermissions with **admin consent**, and set `AZURE_AUTH_MODE=clientCredentials`,\n`AZURE_TENANT_ID=<your tenant>`, `AZURE_CLIENT_SECRET=...`. Note app‑only has **limited Flow\nreach** (it generally cannot see personal \"My Flows\").\n\n### Verified working setup ⚠️\n\nConfirmed against a real tenant. Interactive Flow auth needs **all four** of these — each one,\nif missing, fails with a different cryptic `AADSTS…` (details in [`docs/api-notes.md`](docs/api-notes.md)):\n\n1. **A specific tenant** — `AZURE_TENANT_ID=<your-tenant-GUID>`, **not `common`**. `common` + a\n   resource scope → `AADSTS50059` (and MSAL hides it as an empty device-code response).\n2. **The _Microsoft Flow Service_ delegated permission** on the app (resource app id\n   `7df0a125-d3be-4c96-aa54-591f83ff541c`). Missing → `AADSTS650057`.\n3. **Specific scopes, not `.default`**, when reusing an app that has other (incrementally\n   consented) permissions — `.default` validates the whole app and can fail with `AADSTS650051`.\n   A _dedicated_ app may use `.default`. Pin via `FLOW_SCOPES`.\n4. **\"Allow public client flows\" = Yes** (`isFallbackPublicClient=true`). Off → token redemption\n   fails with `invalid_client`.\n\nVerified `FLOW_SCOPES`:\n`https://service.flow.microsoft.com/Flows.Read.All,https://service.flow.microsoft.com/Flows.Manage.All`\n\n#### Configure an existing app via `az`\n\n```bash\nAPP=<your-app-client-id>; FLOW=7df0a125-d3be-4c96-aa54-591f83ff541c\n# Flows.Read.All + Flows.Manage.All (delegated), then tenant-wide consent:\naz ad app permission add --id \"$APP\" --api \"$FLOW\" --api-permissions \\\n  e45c5562-459d-4d1b-8148-83eb1b6dcf83=Scope 30b2d850-00c3-4802-b7ae-ece9af9de5c6=Scope\naz ad app permission admin-consent --id \"$APP\"\n# enable device-code (public client flows):\naz ad app update --id \"$APP\" --set isFallbackPublicClient=true\n```\n\n> **Recommended:** a **dedicated** public-client app with only the Flow delegated permissions\n> avoids the `.default`/shared-app pitfalls (#3) entirely — cleaner than reusing a Graph app.\n\n## Tools\n\nAll tools are **read‑only by default**. Write tools are registered but **refuse** unless\n`ENABLE_WRITE_OPS=true`.\n\n### Read-only (always enabled)\n\n| Tool                | Parameters                                       | Returns                                                                    |\n| ------------------- | ------------------------------------------------ | -------------------------------------------------------------------------- |\n| `list_environments` | —                                                | `{ id, name, displayName, location, isDefault }[]`                         |\n| `list_flows`        | `environment?`, `owner?`                         | `{ name, displayName, state, createdTime, lastModifiedTime, owner }[]`     |\n| `get_flow`          | `environment?`, `flow`                           | full flow incl. `definition`, `connectionReferences`, trigger/action names |\n| `list_flow_runs`    | `environment?`, `flow`, `top?` (≤100), `status?` | `{ name, status, startTime, endTime, durationMs, triggerName, error }[]`   |\n| `get_flow_run`      | `environment?`, `flow`, `run`                    | run detail + first‑failure + `raw` properties (debugging)                  |\n| `list_connections`  | `environment?`                                   | `{ name, apiName, displayName, status, accountName, expiresAt }[]`         |\n| `list_flow_owners`  | `environment?`, `flow`                           | `{ principalId, principalType, roleName, principalDisplayName }[]`         |\n\n### Write (require `ENABLE_WRITE_OPS=true`)\n\n| Tool                           | Parameters                                                                                     |\n| ------------------------------ | ---------------------------------------------------------------------------------------------- |\n| `create_flow`                  | `environment?`, `displayName`, `definition`, `connectionReferences?`, `state?`                 |\n| `update_flow`                  | `environment?`, `flow`, any of `displayName` / `definition` / `state` / `connectionReferences` |\n| `delete_flow`                  | `environment?`, `flow`, `confirm` (must be `true`)                                             |\n| `enable_flow` / `disable_flow` | `environment?`, `flow`                                                                         |\n| `cancel_flow_run`              | `environment?`, `flow`, `run`                                                                  |\n| `resubmit_flow_run`            | `environment?`, `flow`, `run`, `trigger`                                                       |\n| `add_flow_owner`               | `environment?`, `flow`, `principalId`, `roleName` (`CanEdit`\\|`CanView`)                       |\n| `remove_flow_owner`            | `environment?`, `flow`, `principalId`                                                          |\n\n> **Authoring (`create_flow`/`update_flow`):** `definition` is the raw Logic Apps-style\n> workflow JSON (see `get_flow` output as a template). The visual designer is better for\n> complex logic; for edits, `get_flow` → modify the `definition` → pass it back to `update_flow`.\n\nWhen `environment` is omitted, tools use `DEFAULT_ENVIRONMENT` if set, else the discovered\ndefault environment (`isDefault: true`).\n\n### Built-in (from SomaMCP)\n\n- `info` MCP tool — server name, version, git SHA, capability counts.\n- `report_feedback` — file API‑drift/bug reports as GitHub issues (`FEEDBACK_GITHUB_REPO`,\n  `GITHUB_TOKEN`).\n- HTTP endpoints `/health`, `/health/detail`, `/info`, `/dashboard` (the detailed ones are\n  protected by `MCP_API_KEY` when set).\n\n## Configuration\n\nSee [`.env.example`](.env.example) for the full list. Highlights: `AZURE_CLIENT_ID` (required),\n`AZURE_TENANT_ID` (`common`), `AZURE_AUTH_MODE`, `TRANSPORT` (`stdio`\\|`http`), `PORT`,\n`ENABLE_WRITE_OPS`, `DEFAULT_ENVIRONMENT`, `MCP_API_KEY`, `TELEMETRY`, `TOKEN_CACHE_PATH`.\n\n## Transports & deployment\n\n| Scenario                | Transport | Auth                                   | Notes                                                                        |\n| ----------------------- | --------- | -------------------------------------- | ---------------------------------------------------------------------------- |\n| Local agent             | `stdio`   | device-code                            | Primary. Full reach. `pnpm dev:stdio`.                                       |\n| Docker, single operator | `http`    | device-code + **mounted token volume** | Auth once via `docker logs`; persists. Full reach. `docker compose up`.      |\n| Docker, unattended      | `http`    | `clientCredentials`                    | No human, but **no personal flows**; verify it can mint a Flow token at all. |\n\n> [!WARNING]\n> **The HTTP transport is single-operator.** Every caller shares one Power Automate\n> identity: the server holds a single process-wide token (one device-code sign-in, or one\n> app identity), and `MCP_API_KEY` is a shared static bearer that gates _access_, not\n> _identity_. Do **not** expose the HTTP endpoint to multiple users expecting per-user\n> separation — they would all see and mutate the same person's flows. For per-user\n> isolation, run **stdio** (one process per user, how Claude Desktop already runs it) or\n> wait for the v2 per-user OAuth path\n> ([#9](https://github.com/sapientsai/power-automate-mcp-server/issues/9)).\n\n> **v2:** per‑user browser OAuth over HTTP via FastMCP's `AzureProvider` + disk token cache\n> (the upstream token surfaces on the session). Reachable through SomaMCP's `backendOptions`\n> passthrough without a fork — not wired in v1.\n\n```bash\n# Docker (single-operator device-code with a persisted token volume)\nAZURE_CLIENT_ID=... docker compose up --build\ndocker compose logs -f          # grab the device code on first run\ncurl -s http://localhost:3333/health\n```\n\n## Development\n\n```bash\npnpm validate        # format + lint + typecheck + test + build\npnpm test            # vitest (unit)\npnpm dev             # http transport, watch\npnpm dev:stdio       # stdio transport, watch\npnpm build           # tsdown -> dist/\n```\n\nIntegration tests that hit a real tenant live under `test/integration/` and run only with\n`INTEGRATION=1` (see that folder's README). CI runs unit tests only.\n\n## Troubleshooting\n\n- **Device code never grants a token / \"device-code sign-in failed for all scope candidates\"**\n  → the Flow audience isn't grantable to your app. See \"Token audience\" and `docs/api-notes.md`.\n- **`auth error` on every call** → token cache stale; restart to re‑auth, or delete\n  `TOKEN_CACHE_PATH`.\n- **`not found` on a known flow** → wrong environment; run `list_environments` / `list_flows`\n  first. The flow `name` is the GUID, not the display name.\n- **`forbidden`** → the signed‑in user lacks permission on that flow.\n- **Empty `list_flows`** in `clientCredentials` mode → app‑only can't see personal flows; use\n  `interactive`.\n- **An endpoint 404/410s unexpectedly** → Microsoft may have moved the api‑version; check the\n  portal's network tab and pin a newer `api-version` (see `docs/api-notes.md`).\n\n## License\n\nMIT.\n\n---\n\n**Sponsored by <a href=\"https://sapientsai.com/\"><img src=\"https://sapientsai.com/images/logo.svg\" alt=\"SapientsAI\" width=\"20\" style=\"vertical-align: middle;\"> SapientsAI</a>** — Building agentic AI for businesses\n",
  "bytes": 13195,
  "sha": "63364a279a9404a7a86418fe29e61659af237c757d793a6afe4f56bbd2508b1a",
  "repo_slug": "sapientsai/power-automate-mcp-server",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_sapientsai_power_automate_mcp__b7d15a6f/readme"
}