Back to the catalog

io.github.sapientsai/power-automate-mcp-server

Inspect, operate, and author Microsoft Power Automate cloud flows from an agent context.

Open source Open in the app JSON README (API)

About

Inspect, operate, and author Microsoft Power Automate cloud flows from an agent context.

Details

Kind
MCP servers
Topic
No topic detected
Publisher
sapientsai
Origin
official
Category
ferramentas
Transport
local
Version
0.2.4
Stars
2
Open pull requests
5
Last push
2026-08-17T00:25:34Z
Repository state
ativo
Language
TypeScript
License
MIT
Added
2026-08-29 04:01:21
Updated
2026-08-29 04:01:21
Origin id
io.github.sapientsai/power-automate-mcp-server

README

# power-automate-mcp-server

[![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)
[![npm version](https://img.shields.io/npm/v/power-automate-mcp-server.svg)](https://www.npmjs.com/package/power-automate-mcp-server)
[![npm downloads](https://img.shields.io/npm/dm/power-automate-mcp-server.svg)](https://www.npmjs.com/package/power-automate-mcp-server)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

An MCP server that lets agents **inspect, operate, and author Microsoft Power Automate cloud
flows** from a CLI/agent context — list and inspect flows, debug runs, check connections and
owners, and (when explicitly enabled) enable/disable flows, cancel/resubmit runs, manage
owners, and **create/update/delete flows**.

Primarily a **management** surface — the Power Automate portal's visual designer remains the
better place to author complex flow logic — but `create_flow`/`update_flow`/`delete_flow` are
also available (write-gated) for programmatic authoring. Built on
[SomaMCP](https://github.com/sapientsai/SomaMCP) (telemetry, health/info/
dashboard, error classification) over FastMCP.

> ⚠️ **Unofficial API.** v1 targets `api.flow.microsoft.com` — the surface the Power Automate
> portal itself uses. Microsoft labels it _"isn't supported. Customers should instead use the
> Dataverse Web APIs."_ It is stable in practice and, unlike Dataverse, sees **all** flows
> (including personal "My Flows") and works on M365‑seeded entitlements (no Premium license).
> Every tool's description carries this disclaimer. A supported Dataverse backend is stubbed
> for the future (see [`src/backend/dataverse/README.md`](src/backend/dataverse/README.md)).

## Quick start

```bash
pnpm install
cp .env.example .env          # set AZURE_CLIENT_ID (see "App registration" below)
pnpm build
pnpm dev:stdio                # local agent over stdio (device-code sign-in to stderr)
```

On first use the server prints a device-code prompt to **stderr**; open
`https://microsoft.com/devicelogin`, enter the code, and sign in. The token is cached
(`TOKEN_CACHE_PATH`, mode 0600) and silently refreshed thereafter.

### Add to an MCP client (stdio)

```jsonc
{
  "mcpServers": {
    "power-automate": {
      "command": "npx",
      "args": ["-y", "power-automate-mcp-server", "--stdio"],
      "env": { "AZURE_CLIENT_ID": "<your-app-registration-client-id>" },
    },
  },
}
```

**Developing on this repo?** It ships a project-scoped [`.mcp.json`](.mcp.json) (stdio, local
`dist/bin.js`). After `pnpm build`, export `AZURE_CLIENT_ID` and open the repo in Claude Code —
the `power-automate` server loads automatically (complete the device-code sign-in once; the
cached token is then reused).

## App registration

This server ships **no** default client id — you register your own (one‑time):

1. **Azure Portal → Microsoft Entra ID → App registrations → New registration.**
2. Name it (e.g. `power-automate-mcp`). Supported account types: **multitenant** (or
   single‑tenant if you'll only ever use one org).
3. **Authentication → Add a platform → Mobile and desktop applications.** Add redirect URI
   `http://localhost` (unused by device code, but required to register the platform). Set
   **"Allow public client flows" = Yes**.
4. **API permissions → Add a permission.** You need a **delegated** permission for the Power
   Automate / _Microsoft Flow Service_ API. If it isn't in the picker, see "Token audience"
   below — this is the known friction point.
5. Copy the **Application (client) ID** → `AZURE_CLIENT_ID`.

For unattended `clientCredentials` mode instead: add a **client secret**, grant **application**
permissions with **admin consent**, and set `AZURE_AUTH_MODE=clientCredentials`,
`AZURE_TENANT_ID=<your tenant>`, `AZURE_CLIENT_SECRET=...`. Note app‑only has **limited Flow
reach** (it generally cannot see personal "My Flows").

### Verified working setup ⚠️

Confirmed against a real tenant. Interactive Flow auth needs **all four** of these — each one,
if missing, fails with a different cryptic `AADSTS…` (details in [`docs/api-notes.md`](docs/api-notes.md)):

1. **A specific tenant** — `AZURE_TENANT_ID=<your-tenant-GUID>`, **not `common`**. `common` + a
   resource scope → `AADSTS50059` (and MSAL hides it as an empty device-code response).
2. **The _Microsoft Flow Service_ delegated permission** on the app (resource app id
   `7df0a125-d3be-4c96-aa54-591f83ff541c`). Missing → `AADSTS650057`.
3. **Specific scopes, not `.default`**, when reusing an app that has other (incrementally
   consented) permissions — `.default` validates the whole app and can fail with `AADSTS650051`.
   A _dedicated_ app may use `.default`. Pin via `FLOW_SCOPES`.
4. **"Allow public client flows" = Yes** (`isFallbackPublicClient=true`). Off → token redemption
   fails with `invalid_client`.

Verified `FLOW_SCOPES`:
`https://service.flow.microsoft.com/Flows.Read.All,https://service.flow.microsoft.com/Flows.Manage.All`

#### Configure an existing app via `az`

```bash
APP=<your-app-client-id>; FLOW=7df0a125-d3be-4c96-aa54-591f83ff541c
# Flows.Read.All + Flows.Manage.All (delegated), then tenant-wide consent:
az ad app permission add --id "$APP" --api "$FLOW" --api-permissions \
  e45c5562-459d-4d1b-8148-83eb1b6dcf83=Scope 30b2d850-00c3-4802-b7ae-ece9af9de5c6=Scope
az ad app permission admin-consent --id "$APP"
# enable device-code (public client flows):
az ad app update --id "$APP" --set isFallbackPublicClient=true
```

> **Recommended:** a **dedicated** public-client app with only the Flow delegated permissions
> avoids the `.default`/shared-app pitfalls (#3) entirely — cleaner than reusing a Graph app.

## Tools

All tools are **read‑only by default**. Write tools are registered but **refuse** unless
`ENABLE_WRITE_OPS=true`.

### Read-only (always enabled)

| Tool                | Parameters                                       | Returns                                                                    |
| ------------------- | ------------------------------------------------ | -------------------------------------------------------------------------- |
| `list_environments` | —                                                | `{ id, name, displayName, location, isDefault }[]`                         |
| `list_flows`        | `environment?`, `owner?`                         | `{ name, displayName, state, createdTime, lastModifiedTime, owner }[]`     |
| `get_flow`          | `environment?`, `flow`                           | full flow incl. `definition`, `connectionReferences`, trigger/action names |
| `list_flow_runs`    | `environment?`, `flow`, `top?` (≤100), `status?` | `{ name, status, startTime, endTime, durationMs, triggerName, error }[]`   |
| `get_flow_run`      | `environment?`, `flow`, `run`                    | run detail + first‑failure + `raw` properties (debugging)                  |
| `list_connections`  | `environment?`                                   | `{ name, apiName, displayName, status, accountName, expiresAt }[]`         |
| `list_flow_owners`  | `environment?`, `flow`                           | `{ principalId, principalType, roleName, principalDisplayName }[]`         |

### Write (require `ENABLE_WRITE_OPS=true`)

| Tool                           | Parameters                                                                                     |
| ------------------------------ | ---------------------------------------------------------------------------------------------- |
| `create_flow`                  | `environment?`, `displayName`, `definition`, `connectionReferences?`, `state?`                 |
| `update_flow`                  | `environment?`, `flow`, any of `displayName` / `definition` / `state` / `connectionReferences` |
| `delete_flow`                  | `environment?`, `flow`, `confirm` (must be `true`)                                             |
| `enable_flow` / `disable_flow` | `environment?`, `flow`                                                                         |
| `cancel_flow_run`              | `environment?`, `flow`, `run`                                                                  |
| `resubmit_flow_run`            | `environment?`, `flow`, `run`, `trigger`                                                       |
| `add_flow_owner`               | `environment?`, `flow`, `principalId`, `roleName` (`CanEdit`\|`CanView`)                       |
| `remove_flow_owner`            | `environment?`, `flow`, `principalId`                                                          |

> **Authoring (`create_flow`/`update_flow`):** `definition` is the raw Logic Apps-style
> workflow JSON (see `get_flow` output as a template). The visual designer is better for
> complex logic; for edits, `get_flow` → modify the `definition` → pass it back to `update_flow`.

When `environment` is omitted, tools use `DEFAULT_ENVIRONMENT` if set, else the discovered
default environment (`isDefault: true`).

### Built-in (from SomaMCP)

- `info` MCP tool — server name, version, git SHA, capability counts.
- `report_feedback` — file API‑drift/bug reports as GitHub issues (`FEEDBACK_GITHUB_REPO`,
  `GITHUB_TOKEN`).
- HTTP endpoints `/health`, `/health/detail`, `/info`, `/dashboard` (the detailed ones are
  protected by `MCP_API_KEY` when set).

## Configuration

See [`.env.example`](.env.example) for the full list. Highlights: `AZURE_CLIENT_ID` (required),
`AZURE_TENANT_ID` (`common`), `AZURE_AUTH_MODE`, `TRANSPORT` (`stdio`\|`http`), `PORT`,
`ENABLE_WRITE_OPS`, `DEFAULT_ENVIRONMENT`, `MCP_API_KEY`, `TELEMETRY`, `TOKEN_CACHE_PATH`.

## Transports & deployment

| Scenario                | Transport | Auth                                   | Notes                                                                        |
| ----------------------- | --------- | -------------------------------------- | ---------------------------------------------------------------------------- |
| Local agent             | `stdio`   | device-code                            | Primary. Full reach. `pnpm dev:stdio`.                                       |
| Docker, single operator | `http`    | device-code + **mounted token volume** | Auth once via `docker logs`; persists. Full reach. `docker compose up`.      |
| Docker, unattended      | `http`    | `clientCredentials`                    | No human, but **no personal flows**; verify it can mint a Flow token at all. |

> [!WARNING]
> **The HTTP transport is single-operator.** Every caller shares one Power Automate
> identity: the server holds a single process-wide token (one device-code sign-in, or one
> app identity), and `MCP_API_KEY` is a shared static bearer that gates _access_, not
> _identity_. Do **not** expose the HTTP endpoint to multiple users expecting per-user
> separation — they would all see and mutate the same person's flows. For per-user
> isolation, run **stdio** (one process per user, how Claude Desktop already runs it) or
> wait for the v2 per-user OAuth path
> ([#9](https://github.com/sapientsai/power-automate-mcp-server/issues/9)).

> **v2:** per‑user browser OAuth over HTTP via FastMCP's `AzureProvider` + disk token cache
> (the upstream token surfaces on the session). Reachable through SomaMCP's `backendOptions`
> passthrough without a fork — not wired in v1.

```bash
# Docker (single-operator device-code with a persisted token volume)
AZURE_CLIENT_ID=... docker compose up --build
docker compose logs -f          # grab the device code on first run
curl -s http://localhost:3333/health
```

## Development

```bash
pnpm validate        # format + lint + typecheck + test + build
pnpm test            # vitest (unit)
pnpm dev             # http transport, watch
pnpm dev:stdio       # stdio transport, watch
pnpm build           # tsdown -> dist/
```

Integration tests that hit a real tenant live under `test/integration/` and run only with
`INTEGRATION=1` (see that folder's README). CI runs unit tests only.

## Troubleshooting

- **Device code never grants a token / "device-code sign-in failed for all scope candidates"**
  → the Flow audience isn't grantable to your app. See "Token audience" and `docs/api-notes.md`.
- **`auth error` on every call** → token cache stale; restart to re‑auth, or delete
  `TOKEN_CACHE_PATH`.
- **`not found` on a known flow** → wrong environment; run `list_environments` / `list_flows`
  first. The flow `name` is the GUID, not the display name.
- **`forbidden`** → the signed‑in user lacks permission on that flow.
- **Empty `list_flows`** in `clientCredentials` mode → app‑only can't see personal flows; use
  `interactive`.
- **An endpoint 404/410s unexpectedly** → Microsoft may have moved the api‑version; check the
  portal's network tab and pin a newer `api-version` (see `docs/api-notes.md`).

## License

MIT.

---

**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

More