Skip to content

Commit 1f8cd2f

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 5ebf14d commit 1f8cd2f

3 files changed

Lines changed: 79 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.0",
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: 2 additions & 2 deletions
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.0",
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",
@@ -17,4 +17,4 @@
1717
"power-platform",
1818
"flowagent"
1919
]
20-
}
20+
}

plugins/power-automate/server/mcp.mjs

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/usr/bin/env node
2-
// FlowAgent MCP v2.5.0
32
var __create = Object.create;
43
var __defProp = Object.defineProperty;
54
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -27701,9 +27700,9 @@ function dataverseConnectionReferencesUrl(instanceUrl, opts) {
2770127700
var PPAPI_API_VERSION = "1";
2770227701
var PPAPI_DEFAULT_SUFFIX = "environment.api.powerplatform.com";
2770327702
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);
27703+
const isDefault = /^Default-/i.test(envId);
27704+
const hex = envId.replace(/^Default-/i, "").toLowerCase().replace(/-/g, "");
27705+
const prefix = (isDefault ? "default" : "") + hex.slice(0, 30);
2770727706
const shard = hex.slice(30, 32);
2770827707
const template = templateOverride ?? process.env.PA_PPAPI_BASE_URL;
2770927708
if (template) {
@@ -28618,6 +28617,7 @@ var FlowClient = class _FlowClient {
2861828617
if (opts.autoResolveConnectionRefs !== false && body.properties?.definition) {
2861928618
autoMerged = await this.autoMergeConnectionRefs(envId, flowId, body);
2862028619
}
28620+
this.stripInjectedAuthentication(body);
2862128621
if (body.properties?.definition) {
2862228622
try {
2862328623
const ctx = await this.getFlowContext(envId, flowId);
@@ -28633,7 +28633,7 @@ var FlowClient = class _FlowClient {
2863328633
logger.debug(`updateFlow: Dataverse path failed, falling through to PPAPI`);
2863428634
}
2863528635
}
28636-
this.stripInjectedAuthentication(body);
28636+
this.rewriteConnectionNamesForPpapi(body);
2863728637
const path5 = `/powerautomate/flows/${flowId}${this.ppapiFlowQs({})}`;
2863828638
const result = await this.ppapiRequestWithFallback(envId, path5, "PATCH", body);
2863928639
if (autoMerged.length)
@@ -28732,12 +28732,57 @@ var FlowClient = class _FlowClient {
2873228732
}
2873328733
/**
2873428734
* 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
28735+
* These cause WorkflowRunActionInputsInvalidProperty on write — applies to BOTH
28736+
* the PPAPI and Dataverse write paths (#360).
28737+
*
28738+
* Walks top-level actions and triggers, plus common nesting containers
28739+
* (If/else, Switch cases, Scope, Foreach, Until) so nested actions are covered.
28740+
*/
28741+
stripInjectedAuthentication(body) {
28742+
const def = body.properties?.definition;
28743+
if (!def)
28744+
return;
28745+
const stripAuth = (inputs) => {
28746+
if (!inputs || typeof inputs !== "object" || Array.isArray(inputs))
28747+
return;
28748+
const inp = inputs;
28749+
if ("authentication" in inp)
28750+
delete inp.authentication;
28751+
};
28752+
const walkActions = (actions) => {
28753+
if (!actions || typeof actions !== "object" || Array.isArray(actions))
28754+
return;
28755+
for (const action of Object.values(actions)) {
28756+
stripAuth(action?.inputs);
28757+
if (action?.actions)
28758+
walkActions(action.actions);
28759+
if (action?.else?.actions)
28760+
walkActions(action.else.actions);
28761+
if (action?.cases) {
28762+
for (const c of Object.values(action.cases)) {
28763+
if (c?.actions)
28764+
walkActions(c.actions);
28765+
}
28766+
}
28767+
}
28768+
};
28769+
walkActions(def.actions);
28770+
const triggers = def.triggers;
28771+
if (triggers) {
28772+
for (const trigger of Object.values(triggers)) {
28773+
stripAuth(trigger?.inputs);
28774+
}
28775+
}
28776+
}
28777+
/**
28778+
* Translate `host.connectionName` to `host.connectionReferenceName` for solution
28779+
* flows where PPAPI returns connectionName but the PPAPI write API requires
2873828780
* connectionReferenceName (#314 finding 2).
28781+
*
28782+
* NOT called for the Dataverse write path — Dataverse clientdata stores the
28783+
* native format (connectionName) and the rewrite would corrupt it.
2873928784
*/
28740-
stripInjectedAuthentication(body, connectionReferences) {
28785+
rewriteConnectionNamesForPpapi(body, connectionReferences) {
2874128786
const def = body.properties?.definition;
2874228787
if (!def)
2874328788
return;
@@ -28750,12 +28795,12 @@ var FlowClient = class _FlowClient {
2875028795
}
2875128796
}
2875228797
}
28798+
if (Object.keys(connRefMap).length === 0)
28799+
return;
2875328800
const fixHost = (inputs) => {
2875428801
if (!inputs || typeof inputs !== "object" || Array.isArray(inputs))
2875528802
return;
2875628803
const inp = inputs;
28757-
if ("authentication" in inp)
28758-
delete inp.authentication;
2875928804
const host = inp.host;
2876028805
if (host && host.connectionName && !host.connectionReferenceName) {
2876128806
const logicalName = connRefMap[host.connectionName];
@@ -28765,12 +28810,24 @@ var FlowClient = class _FlowClient {
2876528810
}
2876628811
}
2876728812
};
28768-
const actions = def.actions;
28769-
if (actions) {
28813+
const walkActions = (actions) => {
28814+
if (!actions || typeof actions !== "object" || Array.isArray(actions))
28815+
return;
2877028816
for (const action of Object.values(actions)) {
2877128817
fixHost(action?.inputs);
28818+
if (action?.actions)
28819+
walkActions(action.actions);
28820+
if (action?.else?.actions)
28821+
walkActions(action.else.actions);
28822+
if (action?.cases) {
28823+
for (const c of Object.values(action.cases)) {
28824+
if (c?.actions)
28825+
walkActions(c.actions);
28826+
}
28827+
}
2877228828
}
28773-
}
28829+
};
28830+
walkActions(def.actions);
2877428831
const triggers = def.triggers;
2877528832
if (triggers) {
2877628833
for (const trigger of Object.values(triggers)) {
@@ -43106,9 +43163,9 @@ async function createMcpServer(authProvider, deps = {}) {
4310643163
try {
4310743164
const opts = {};
4310843165
if (query)
43109-
opts.searchText = query;
43166+
opts.query = query;
4311043167
if (connector)
43111-
opts.operationGroupName = connector;
43168+
opts.connector = connector;
4311243169
opts.top = top || 20;
4311343170
const results = await ctx.getClient().searchOperations(ctx.resolveEnv(env), opts);
4311443171
const s = (Array.isArray(results) ? results : []).map((op) => ({
@@ -43128,13 +43185,14 @@ async function createMcpServer(authProvider, deps = {}) {
4312843185
const schema = await ctx.getClient().getOperationSchema(ctx.resolveEnv(env), connector, operation);
4312943186
const props = schema?.properties ?? schema;
4313043187
const inputs = props?.inputsDefinition ?? {};
43131-
const params = inputs?.parameters ?? {};
43188+
const params = inputs?.properties ?? inputs?.parameters ?? {};
43189+
const requiredSet = new Set(Array.isArray(inputs?.required) ? inputs.required : []);
4313243190
return safeResult({
4313343191
operationId: operation,
4313443192
connector,
4313543193
summary: props?.summary ?? props?.description,
4313643194
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 }]))
43195+
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 }]))
4313843196
});
4313943197
} catch (e) {
4314043198
return safeError(e);

0 commit comments

Comments
 (0)