Skip to content

Commit b6d6e04

Browse files
author
Matt Townsend
committed
feat(power-automate): v3.0.0 — MCP SDK v2, stateless protocol, zod 4
Major update: migrates from @modelcontextprotocol/sdk@1.30.0 to @modelcontextprotocol/server@2.0.0 (2026-07-28 stateless MCP spec). Breaking: requires Node.js >=20 (v2 SDK requirement). Changes: - MCP SDK v2 with stateless protocol support - zod 4 schemas (v4-native, accepted by v2 registerTool) - createRequire banner for CJS interop in ESM bundle - All prior fixes preserved (PPAPI DNS fallback, Button trigger fix) Verified: 56 tools, 116 core tests pass, bundle starts cleanly.
1 parent 59da1af commit b6d6e04

3 files changed

Lines changed: 84 additions & 21 deletions

File tree

plugins/power-automate/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "power-automate",
3-
"version": "2.5.0",
3+
"version": "3.0.1",
44
"description": "Build, edit, run, and debug Power Automate cloud flows via the FlowAgent MCP server — connection lifecycle, surgical edits, copy across environments, run management, and validated expressions.",
55
"author": {
66
"name": "Microsoft",

plugins/power-automate/.plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "power-automate",
3-
"version": "2.5.0",
3+
"version": "3.0.1",
44
"description": "Build, edit, run, and debug Power Automate cloud flows via the FlowAgent MCP server — connection lifecycle, surgical edits, copy across environments, run management, and validated expressions.",
55
"author": {
66
"name": "Microsoft",

plugins/power-automate/server/mcp.mjs

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env node
2-
// FlowAgent MCP v2.5.0
2+
import{createRequire}from'module';const require=createRequire(import.meta.url);
33
var __create = Object.create;
44
var __defProp = Object.defineProperty;
55
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -27701,9 +27701,9 @@ function dataverseConnectionReferencesUrl(instanceUrl, opts) {
2770127701
var PPAPI_API_VERSION = "1";
2770227702
var PPAPI_DEFAULT_SUFFIX = "environment.api.powerplatform.com";
2770327703
function ppapiBaseUrl(envId, templateOverride, suffixOverride) {
27704-
const rawId = envId.replace(/^Default-/i, "");
27705-
const hex = rawId.replace(/-/g, "");
27706-
const prefix = hex.slice(0, 30);
27704+
const isDefault = /^Default-/i.test(envId);
27705+
const hex = envId.replace(/^Default-/i, "").toLowerCase().replace(/-/g, "");
27706+
const prefix = (isDefault ? "default" : "") + hex.slice(0, 30);
2770727707
const shard = hex.slice(30, 32);
2770827708
const template = templateOverride ?? process.env.PA_PPAPI_BASE_URL;
2770927709
if (template) {
@@ -28618,6 +28618,7 @@ var FlowClient = class _FlowClient {
2861828618
if (opts.autoResolveConnectionRefs !== false && body.properties?.definition) {
2861928619
autoMerged = await this.autoMergeConnectionRefs(envId, flowId, body);
2862028620
}
28621+
this.stripInjectedAuthentication(body);
2862128622
if (body.properties?.definition) {
2862228623
try {
2862328624
const ctx = await this.getFlowContext(envId, flowId);
@@ -28633,7 +28634,7 @@ var FlowClient = class _FlowClient {
2863328634
logger.debug(`updateFlow: Dataverse path failed, falling through to PPAPI`);
2863428635
}
2863528636
}
28636-
this.stripInjectedAuthentication(body);
28637+
this.rewriteConnectionNamesForPpapi(body);
2863728638
const path5 = `/powerautomate/flows/${flowId}${this.ppapiFlowQs({})}`;
2863828639
const result = await this.ppapiRequestWithFallback(envId, path5, "PATCH", body);
2863928640
if (autoMerged.length)
@@ -28732,12 +28733,59 @@ var FlowClient = class _FlowClient {
2873228733
}
2873328734
/**
2873428735
* Remove `authentication` fields that PPAPI injects into action inputs on read.
28735-
* These cause WorkflowRunActionInputsInvalidProperty on write.
28736-
* Also translate `host.connectionName` to `host.connectionReferenceName` for
28737-
* solution flows where PPAPI returns connectionName but the API requires
28736+
* These cause WorkflowRunActionInputsInvalidProperty on write — applies to BOTH
28737+
* the PPAPI and Dataverse write paths (#360).
28738+
*
28739+
* Walks top-level actions and triggers, plus common nesting containers
28740+
* (If/else, Switch cases, Scope, Foreach, Until) so nested actions are covered.
28741+
*/
28742+
stripInjectedAuthentication(body) {
28743+
const def = body.properties?.definition;
28744+
if (!def)
28745+
return;
28746+
const stripAuth = (inputs) => {
28747+
if (!inputs || typeof inputs !== "object" || Array.isArray(inputs))
28748+
return;
28749+
const inp = inputs;
28750+
if ("authentication" in inp)
28751+
delete inp.authentication;
28752+
};
28753+
const walkActions = (actions) => {
28754+
if (!actions || typeof actions !== "object" || Array.isArray(actions))
28755+
return;
28756+
for (const action of Object.values(actions)) {
28757+
stripAuth(action?.inputs);
28758+
if (action?.actions)
28759+
walkActions(action.actions);
28760+
if (action?.else?.actions)
28761+
walkActions(action.else.actions);
28762+
if (action?.default?.actions)
28763+
walkActions(action.default.actions);
28764+
if (action?.cases) {
28765+
for (const c of Object.values(action.cases)) {
28766+
if (c?.actions)
28767+
walkActions(c.actions);
28768+
}
28769+
}
28770+
}
28771+
};
28772+
walkActions(def.actions);
28773+
const triggers = def.triggers;
28774+
if (triggers) {
28775+
for (const trigger of Object.values(triggers)) {
28776+
stripAuth(trigger?.inputs);
28777+
}
28778+
}
28779+
}
28780+
/**
28781+
* Translate `host.connectionName` to `host.connectionReferenceName` for solution
28782+
* flows where PPAPI returns connectionName but the PPAPI write API requires
2873828783
* connectionReferenceName (#314 finding 2).
28784+
*
28785+
* NOT called for the Dataverse write path — Dataverse clientdata stores the
28786+
* native format (connectionName) and the rewrite would corrupt it.
2873928787
*/
28740-
stripInjectedAuthentication(body, connectionReferences) {
28788+
rewriteConnectionNamesForPpapi(body, connectionReferences) {
2874128789
const def = body.properties?.definition;
2874228790
if (!def)
2874328791
return;
@@ -28750,12 +28798,12 @@ var FlowClient = class _FlowClient {
2875028798
}
2875128799
}
2875228800
}
28801+
if (Object.keys(connRefMap).length === 0)
28802+
return;
2875328803
const fixHost = (inputs) => {
2875428804
if (!inputs || typeof inputs !== "object" || Array.isArray(inputs))
2875528805
return;
2875628806
const inp = inputs;
28757-
if ("authentication" in inp)
28758-
delete inp.authentication;
2875928807
const host = inp.host;
2876028808
if (host && host.connectionName && !host.connectionReferenceName) {
2876128809
const logicalName = connRefMap[host.connectionName];
@@ -28765,12 +28813,26 @@ var FlowClient = class _FlowClient {
2876528813
}
2876628814
}
2876728815
};
28768-
const actions = def.actions;
28769-
if (actions) {
28816+
const walkActions = (actions) => {
28817+
if (!actions || typeof actions !== "object" || Array.isArray(actions))
28818+
return;
2877028819
for (const action of Object.values(actions)) {
2877128820
fixHost(action?.inputs);
28821+
if (action?.actions)
28822+
walkActions(action.actions);
28823+
if (action?.else?.actions)
28824+
walkActions(action.else.actions);
28825+
if (action?.default?.actions)
28826+
walkActions(action.default.actions);
28827+
if (action?.cases) {
28828+
for (const c of Object.values(action.cases)) {
28829+
if (c?.actions)
28830+
walkActions(c.actions);
28831+
}
28832+
}
2877228833
}
28773-
}
28834+
};
28835+
walkActions(def.actions);
2877428836
const triggers = def.triggers;
2877528837
if (triggers) {
2877628838
for (const trigger of Object.values(triggers)) {
@@ -42224,7 +42286,7 @@ var jsonRecord = external_exports.preprocess((v) => {
4222442286
}
4222542287
}
4222642288
return v;
42227-
}, external_exports.record(external_exports.unknown()));
42289+
}, external_exports.record(external_exports.string(), external_exports.unknown()));
4222842290
function buildToolContext(mcpCtx, config3, clientFactory) {
4222942291
let client = null;
4223042292
function getClient() {
@@ -43106,9 +43168,9 @@ async function createMcpServer(authProvider, deps = {}) {
4310643168
try {
4310743169
const opts = {};
4310843170
if (query)
43109-
opts.searchText = query;
43171+
opts.query = query;
4311043172
if (connector)
43111-
opts.operationGroupName = connector;
43173+
opts.connector = connector;
4311243174
opts.top = top || 20;
4311343175
const results = await ctx.getClient().searchOperations(ctx.resolveEnv(env), opts);
4311443176
const s = (Array.isArray(results) ? results : []).map((op) => ({
@@ -43128,13 +43190,14 @@ async function createMcpServer(authProvider, deps = {}) {
4312843190
const schema = await ctx.getClient().getOperationSchema(ctx.resolveEnv(env), connector, operation);
4312943191
const props = schema?.properties ?? schema;
4313043192
const inputs = props?.inputsDefinition ?? {};
43131-
const params = inputs?.parameters ?? {};
43193+
const params = inputs?.properties ?? inputs?.parameters ?? {};
43194+
const requiredSet = new Set(Array.isArray(inputs?.required) ? inputs.required : []);
4313243195
return safeResult({
4313343196
operationId: operation,
4313443197
connector,
4313543198
summary: props?.summary ?? props?.description,
4313643199
actionType: inferActionType(props),
43137-
parameters: Object.fromEntries(Object.entries(params).map(([k, v]) => [k, { type: v?.type, required: v?.required ?? false, description: v?.summary ?? v?.description, enum: v?.enum, default: v?.default, dynamicValues: v?.["x-ms-dynamic-values"] ? true : void 0, dynamicTree: v?.["x-ms-dynamic-tree"] ? true : void 0 }]))
43200+
parameters: Object.fromEntries(Object.entries(params).map(([k, v]) => [k, { type: v?.type, required: requiredSet.has(k) || v?.required === true, description: v?.summary ?? v?.description, enum: v?.enum, default: v?.default, dynamicValues: v?.["x-ms-dynamic-values"] ? true : void 0, dynamicTree: v?.["x-ms-dynamic-tree"] ? true : void 0 }]))
4313843201
});
4313943202
} catch (e) {
4314043203
return safeError(e);

0 commit comments

Comments
 (0)