powerautomate-mcp 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +72 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24,7 +24,13 @@ var EnvironmentSchema = z.object({
|
|
|
24
24
|
/** Azure region (e.g., "unitedstates", "europe") */
|
|
25
25
|
region: z.string().min(1),
|
|
26
26
|
/** Human-readable name */
|
|
27
|
-
displayName: z.string().optional()
|
|
27
|
+
displayName: z.string().optional(),
|
|
28
|
+
/**
|
|
29
|
+
* Optional override for the Dataverse hostname (e.g. "contoso.crm.dynamics.com").
|
|
30
|
+
* When omitted, the MCP resolves it at startup via the BAP admin API and falls
|
|
31
|
+
* back to a region-based guess if that call fails.
|
|
32
|
+
*/
|
|
33
|
+
dataverseUrl: z.string().optional()
|
|
28
34
|
});
|
|
29
35
|
var AuthConfigSchema = z.object({
|
|
30
36
|
/** Microsoft Entra application (client) ID */
|
|
@@ -422,7 +428,8 @@ function resolveEnvironment(config, envNameOrId) {
|
|
|
422
428
|
name: envKey,
|
|
423
429
|
id: envConfig.id,
|
|
424
430
|
region: envConfig.region,
|
|
425
|
-
displayName: envConfig.displayName
|
|
431
|
+
displayName: envConfig.displayName,
|
|
432
|
+
dataverseUrl: envConfig.dataverseUrl
|
|
426
433
|
};
|
|
427
434
|
}
|
|
428
435
|
{
|
|
@@ -609,6 +616,19 @@ function validateRowId(id) {
|
|
|
609
616
|
}
|
|
610
617
|
return id;
|
|
611
618
|
}
|
|
619
|
+
function validateFlowRunId(id) {
|
|
620
|
+
if (typeof id !== "string" || id.length < 10 || id.length > 128) {
|
|
621
|
+
throw new ConfigurationError(
|
|
622
|
+
`Invalid flow run ID format: expected alphanumeric identifier (10-128 chars)`
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
if (!/^[0-9A-Za-z]+$/.test(id)) {
|
|
626
|
+
throw new ConfigurationError(
|
|
627
|
+
`Invalid flow run ID format: expected alphanumeric identifier (10-128 chars)`
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
return id;
|
|
631
|
+
}
|
|
612
632
|
function validateSharePointHostname(hostname) {
|
|
613
633
|
const validPattern = /^[a-z0-9-]+\.sharepoint\.(com|us|de|cn)$/i;
|
|
614
634
|
if (!validPattern.test(hostname)) {
|
|
@@ -1436,7 +1456,7 @@ var FlowManagementApi = class {
|
|
|
1436
1456
|
async getFlowRunActions(flowId, runId, environmentId) {
|
|
1437
1457
|
const envId = environmentId ?? this.defaultEnvironmentId;
|
|
1438
1458
|
const safeFlowId = validateRowId(flowId);
|
|
1439
|
-
const safeRunId =
|
|
1459
|
+
const safeRunId = validateFlowRunId(runId);
|
|
1440
1460
|
apiLogger.debug({ flowId: safeFlowId, runId: safeRunId, envId }, "Getting flow run actions");
|
|
1441
1461
|
const url = this.buildUrl(envId, `/flows/${safeFlowId}/runs/${safeRunId}/actions`);
|
|
1442
1462
|
const headers = await this.getAuthHeaders();
|
|
@@ -1514,7 +1534,7 @@ var FlowManagementApi = class {
|
|
|
1514
1534
|
async resubmitRun(flowId, runId, environmentId) {
|
|
1515
1535
|
const envId = environmentId ?? this.defaultEnvironmentId;
|
|
1516
1536
|
const safeFlowId = validateRowId(flowId);
|
|
1517
|
-
const safeRunId =
|
|
1537
|
+
const safeRunId = validateFlowRunId(runId);
|
|
1518
1538
|
apiLogger.info({ flowId: safeFlowId, runId: safeRunId, envId }, "Resubmitting flow run");
|
|
1519
1539
|
const flow = await this.getFlow(safeFlowId, envId);
|
|
1520
1540
|
const triggers = flow.properties.definition?.triggers ?? {};
|
|
@@ -1537,7 +1557,7 @@ var FlowManagementApi = class {
|
|
|
1537
1557
|
async cancelRun(flowId, runId, environmentId) {
|
|
1538
1558
|
const envId = environmentId ?? this.defaultEnvironmentId;
|
|
1539
1559
|
const safeFlowId = validateRowId(flowId);
|
|
1540
|
-
const safeRunId =
|
|
1560
|
+
const safeRunId = validateFlowRunId(runId);
|
|
1541
1561
|
apiLogger.info({ flowId: safeFlowId, runId: safeRunId, envId }, "Cancelling flow run");
|
|
1542
1562
|
const url = this.buildUrl(envId, `/flows/${safeFlowId}/runs/${safeRunId}/cancel`);
|
|
1543
1563
|
const headers = await this.getAuthHeaders();
|
|
@@ -3607,15 +3627,18 @@ var DataverseApi = class {
|
|
|
3607
3627
|
const select = "$select=LogicalName,DisplayName,EntitySetName,Description,IsCustomEntity,IsManaged,SchemaName,PrimaryIdAttribute,PrimaryNameAttribute";
|
|
3608
3628
|
const parts = [select];
|
|
3609
3629
|
if (options.filter) parts.push(`$filter=${validateODataFilter(options.filter)}`);
|
|
3610
|
-
parts.push(`$top=${options.top ?? 100}`);
|
|
3611
|
-
parts.push("$orderby=LogicalName asc");
|
|
3612
3630
|
const url = this.buildUrl("EntityDefinitions", parts.join("&"));
|
|
3613
3631
|
const headers = await this.getAuthHeaders();
|
|
3632
|
+
const cap = options.top ?? 100;
|
|
3614
3633
|
return wrapApiCall(async () => {
|
|
3615
3634
|
const response = await request(url, { method: "GET", headers });
|
|
3616
3635
|
const data = await this.handleResponse(response, "List tables");
|
|
3617
|
-
|
|
3618
|
-
|
|
3636
|
+
const sorted = [...data.value].sort(
|
|
3637
|
+
(a, b) => a.LogicalName.localeCompare(b.LogicalName)
|
|
3638
|
+
);
|
|
3639
|
+
const limited = sorted.slice(0, cap);
|
|
3640
|
+
logger2.info({ count: limited.length, total: data.value.length }, "Listed Dataverse tables");
|
|
3641
|
+
return limited;
|
|
3619
3642
|
}, "List tables");
|
|
3620
3643
|
}
|
|
3621
3644
|
/**
|
|
@@ -3747,8 +3770,12 @@ var DataverseApi = class {
|
|
|
3747
3770
|
// Environment Discovery
|
|
3748
3771
|
// ==========================================================================
|
|
3749
3772
|
/**
|
|
3750
|
-
*
|
|
3751
|
-
*
|
|
3773
|
+
* Construct a best-guess Dataverse hostname from an environment GUID + region.
|
|
3774
|
+
*
|
|
3775
|
+
* WARNING: this is a last-resort fallback. The real Dataverse hostname is the
|
|
3776
|
+
* org's `domainName` (exposed as `linkedEnvironmentMetadata.instanceUrl` on the
|
|
3777
|
+
* BAP admin API) which usually does NOT match the environment GUID. Prefer
|
|
3778
|
+
* resolving instanceUrl from BAP, or set `dataverseUrl` in the env config.
|
|
3752
3779
|
*/
|
|
3753
3780
|
static getDataverseUrl(environmentId, region = "crm") {
|
|
3754
3781
|
const regionMap = {
|
|
@@ -14566,15 +14593,34 @@ async function createMcpServer(serverConfig) {
|
|
|
14566
14593
|
});
|
|
14567
14594
|
let dataverseApi = null;
|
|
14568
14595
|
try {
|
|
14569
|
-
|
|
14570
|
-
|
|
14571
|
-
|
|
14572
|
-
|
|
14596
|
+
let dataverseUrl;
|
|
14597
|
+
let source = "fallback";
|
|
14598
|
+
if (defaultEnv.dataverseUrl) {
|
|
14599
|
+
dataverseUrl = defaultEnv.dataverseUrl;
|
|
14600
|
+
source = "config";
|
|
14601
|
+
} else {
|
|
14602
|
+
try {
|
|
14603
|
+
const envDetail = await adminApi.getEnvironment(defaultEnv.id);
|
|
14604
|
+
const instanceUrl = envDetail.properties?.linkedEnvironmentMetadata?.instanceUrl;
|
|
14605
|
+
if (instanceUrl) {
|
|
14606
|
+
dataverseUrl = instanceUrl;
|
|
14607
|
+
source = "bap";
|
|
14608
|
+
}
|
|
14609
|
+
} catch (err) {
|
|
14610
|
+
logger.warn(
|
|
14611
|
+
{ err: err instanceof Error ? err.message : String(err) },
|
|
14612
|
+
"BAP admin API did not return a Dataverse instanceUrl \u2014 falling back to region guess (may fail DNS)"
|
|
14613
|
+
);
|
|
14614
|
+
}
|
|
14615
|
+
}
|
|
14616
|
+
if (!dataverseUrl) {
|
|
14617
|
+
dataverseUrl = DataverseApi.getDataverseUrl(defaultEnv.id, defaultEnv.region);
|
|
14618
|
+
}
|
|
14573
14619
|
dataverseApi = new DataverseApi({
|
|
14574
14620
|
authProvider,
|
|
14575
14621
|
environmentUrl: dataverseUrl
|
|
14576
14622
|
});
|
|
14577
|
-
logger.info({ dataverseUrl }, "Dataverse API initialized");
|
|
14623
|
+
logger.info({ dataverseUrl, source }, "Dataverse API initialized");
|
|
14578
14624
|
} catch (error) {
|
|
14579
14625
|
logger.warn({ error }, "Failed to initialize Dataverse API \u2014 Dataverse tools will return guidance");
|
|
14580
14626
|
}
|
|
@@ -14853,8 +14899,17 @@ async function createDeviceCodeAuthProvider(config, silentOnly = false) {
|
|
|
14853
14899
|
const deviceCodeRequest = {
|
|
14854
14900
|
scopes: mutableScopes,
|
|
14855
14901
|
deviceCodeCallback: (response) => {
|
|
14902
|
+
const url = response.verificationUri || "https://microsoft.com/devicelogin";
|
|
14903
|
+
const code = response.userCode || "(code missing)";
|
|
14904
|
+
if (!response.message) {
|
|
14905
|
+
logger.warn(
|
|
14906
|
+
{ userCode: code, verificationUri: url },
|
|
14907
|
+
"Device-code response missing 'message' field \u2014 using synthesized fallback"
|
|
14908
|
+
);
|
|
14909
|
+
}
|
|
14910
|
+
const display = response.message || `To sign in, open ${url} in a browser on any device and enter the code ${code} to authenticate.`;
|
|
14856
14911
|
console.log("");
|
|
14857
|
-
console.log(` \x1B[36m?\x1B[0m ${
|
|
14912
|
+
console.log(` \x1B[36m?\x1B[0m ${display}`);
|
|
14858
14913
|
console.log("");
|
|
14859
14914
|
console.log(` \x1B[33m\u26A0\x1B[0m SECURITY: Do not share this code. It expires in ${Math.floor((response.expiresIn ?? 900) / 60)} minutes.`);
|
|
14860
14915
|
console.log("");
|