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 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 = validateRowId(runId);
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 = validateRowId(runId);
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 = validateRowId(runId);
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
- logger2.info({ count: data.value.length }, "Listed Dataverse tables");
3618
- return data.value;
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
- * Discover Dataverse environment URL from Power Platform environment
3751
- * This is needed because Dataverse URL format differs from Flow API
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
- const dataverseUrl = DataverseApi.getDataverseUrl(
14570
- defaultEnv.id,
14571
- defaultEnv.region
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 ${response.message}`);
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("");