Skip to main content

Setup and Configuration

Prerequisites

Before running Flowon Logic Conductor, ensure the following are in place:

RequirementDetails
.NET Runtime.NET 10 or later (the server targets net10.0)
Logic ComposerInstalled and licensed in the target Dataverse environment
Action artifactsAt least one Logic Flow or Logic Block marked as an action in the projects you want to expose
Dataverse ConnectionA Dataverse connection string or service-principal credentials for the target environment
AI ClientAn MCP-compatible AI assistant (Claude, GitHub Copilot, etc.)
Microsoft Entra appRequired only for Secure HTTP mode (JWT Bearer / On-Behalf-Of auth)

Choosing Which Projects to Expose

The one setting that is specific to Flowon Logic Conductor is FLOWON_PROJECTS - the list of Flowon projects whose action artifacts should be turned into tools.

VariablePurpose
FLOWON_PROJECTSThe Flowon project(s) to expose. Every action Logic Flow and Logic Block in these projects becomes an MCP tool.
  • With a single project, tool names are the action name (e.g. approve_credit_limit).
  • With multiple projects, tool names are prefixed with the project name (e.g. sales_approve_credit_limit) to keep them unique.

Scope this narrowly - expose only the projects whose logic you intend an agent to be able to run. See How Tool Generation Works for naming and type-mapping details.

Restart to refresh: Tools are generated at startup. After changing which projects are exposed - or changing the action artifacts inside them - restart the server so the tool catalogue is regenerated.


Host Modes

Flowon Logic Conductor runs in one of three host modes, selected by the --transport argument and the incoming-auth flag.

ModeWhen to useTransportIncoming auth
Stdio (default)Local desktop MCP clientsStandard I/O streamsNone (local process)
HTTPDev / testing onlyPOST /mcpDisabled (--disable-http-incoming-auth); CORS restricted to localhost
Secure HTTPProduction / team-sharedPOST /mcpJWT Bearer (Microsoft Entra ID), with On-Behalf-Of user impersonation

The HostBuilderFactory selects the mode automatically: --transport Http + --disable-http-incoming-authHTTP; --transport Http (without that flag) → Secure HTTP; otherwise → Stdio.


Running the Server

Configuration has two independent axes, plus the Conductor-specific FLOWON_PROJECTS:

  1. Transport + incoming auth — the host mode above (--transport, --disable-http-incoming-auth).
  2. Dataverse (outgoing) auth — how the server authenticates to Dataverse, set with --dataverse-auth-strategy. Connection details are supplied through environment variables, chosen by the strategy. There is no connection-string argument.

CLI Arguments

ArgumentValuesDefault
--transportStdio, HttpStdio
--dataverse-auth-strategyUseHostingEnvironmentIdentity, UseOnBehalfOf, UseClientCredentials, UseUserCredentialsauto
--disable-http-incoming-authflagfalse

Log level is set with the LOG_LEVEL environment variable (TraceError, default Information).

Dataverse Authentication Strategies

StrategyHow the server authenticates to DataverseRequired environment variables
UseHostingEnvironmentIdentityThe host's managed/ambient identity (like DefaultAzureCredential). Ideal for cloud/managed-identity hosting.DATAVERSE_URL
UseOnBehalfOfExchanges the incoming user's token for a Dataverse token — each Logic Flow/Block runs as the calling user. HTTP modes only.DATAVERSE_URL + AzureAd__*
UseClientCredentialsApp-only, using a client id + secret (service principal).DATAVERSE_URL, DATAVERSE_CLIENT_ID, DATAVERSE_CLIENT_SECRET
UseUserCredentialsUsername + password (on-prem Dynamics).DYNAMICS_URL, DYNAMICS_APP_ID, DYNAMICS_USER_NAME, DYNAMICS_PASSWORD

Environment Variables

VariablePurpose
FLOWON_PROJECTSThe Flowon project(s) whose action artifacts become tools
DATAVERSE_URLDataverse environment URL (client-credentials, OBO, and hosting-identity strategies)
DATAVERSE_CLIENT_ID / DATAVERSE_CLIENT_SECRETService-principal credentials (UseClientCredentials)
DYNAMICS_URL / DYNAMICS_APP_ID / DYNAMICS_USER_NAME / DYNAMICS_PASSWORDOn-prem Dynamics credentials (UseUserCredentials)
AzureAd__ClientId, AzureAd__TenantId, AzureAd__Instance, AzureAd__ClientCredentials__0__SourceType, AzureAd__ClientCredentials__0__ClientSecretMicrosoft Entra app registration — required for incoming JWT auth (Secure HTTP) and the OBO token exchange
AZURE_CLOUDAzure sovereign-cloud override
LOG_LEVELTrace, Debug, Information, Warning, Error (default Information)
ASPNETCORE_URLSBind address/port, e.g. http://localhost:1033
FLOWON_MCP_COLLECT_TELEMETRYSet true to emit OpenTelemetry traces/metrics
FLOWON_MCP_DANGEROUSLY_DISABLE_HTTPS_REDIRECTIONSet true to skip HTTPS redirection (useful behind a reverse proxy)
ALLOW_INSECURE_EXTERNAL_BINDINGSet true to allow wildcard/external binding in dev HTTP mode

On-Behalf-Of needs its own app registration. For UseOnBehalfOf, the AzureAd app must expose the MCP API scope and be consented for the on-behalf-of exchange — typically a different registration than the one used for plain client-credentials runs.

⚠️ Never commit real secrets. The values below are placeholders — supply them through your environment, a secret store, or container secrets.

Examples

# HTTP, unauthenticated incoming, app-only Dataverse auth (local dev)
FLOWON_PROJECTS="Sales" \
DATAVERSE_URL="https://yourorg.crm.dynamics.com/" \
DATAVERSE_CLIENT_ID="<app-id>" \
DATAVERSE_CLIENT_SECRET="<secret>" \
ASPNETCORE_URLS="http://localhost:1033" \
dotnet run -- --transport http --disable-http-incoming-auth --dataverse-auth-strategy UseClientCredentials
# Secure HTTP with On-Behalf-Of (each tool call runs as the calling user)
FLOWON_PROJECTS="Sales,Operations" \
DATAVERSE_URL="https://yourorg.crm.dynamics.com/" \
AzureAd__Instance="https://login.microsoftonline.com/" \
AzureAd__TenantId="<tenant-id>" \
AzureAd__ClientId="<obo-app-id>" \
AzureAd__ClientCredentials__0__SourceType="ClientSecret" \
AzureAd__ClientCredentials__0__ClientSecret="<secret>" \
dotnet run -- --transport http --dataverse-auth-strategy UseOnBehalfOf

Endpoints (HTTP modes)

EndpointDescription
POST /mcpThe MCP endpoint. In Secure HTTP mode it requires the McpAccess authorization policy.
GET /healthAnonymous health check (Secure HTTP mode only).
GET /.well-known/oauth-protected-resourceOAuth Protected Resource metadata (RFC 9728) describing the resource, its authorization servers, and supported scopes ({clientId}/Mcp.Tools.ReadWrite). MCP clients use this for discovery.

In Secure HTTP mode, every tool call - i.e. every Logic Flow run or Logic Block evaluation - executes under the calling user's Dynamics identity, resolved from the incoming JWT via the Microsoft Entra On-Behalf-Of (OBO) flow. Dataverse row-level security, business-unit scoping, and team membership apply to every call.


On-Behalf-Of (OBO)

UseOnBehalfOf is the recommended mode for shared, production deployments. Instead of a single service account, the server runs each generated tool as the calling user:

  1. The MCP client calls with the user's access token (Authorization: Bearer …).
  2. The server validates the Entra JWT and enforces the McpAccess policy — the token must carry the delegated scope Mcp.Tools.ReadWrite (or, for app-only callers, the app permission Mcp.Tools.ReadWrite.All).
  3. The server performs the On-Behalf-Of exchange to obtain a downstream Dataverse token for that same user (the token's tenant must match the user's tid claim).
  4. The resulting Logic Flow run / Logic Block evaluation executes with the user's own identity — so a tool can only read and write what that user is permitted to, with row-level security, business-unit scoping, and team membership all applied.

App registration requirements

The AzureAd app used for OBO must be:

  • A confidential client (has a client secret — supplied via AzureAd__ClientCredentials__0__*).
  • Configured to expose an API scope Mcp.Tools.ReadWrite (delegated) and/or an app role Mcp.Tools.ReadWrite.All (app-only).
  • Granted delegated permission to Dataverse (user_impersonation) and admin-consented, so the OBO exchange can succeed.

Wire it up with AzureAd__ClientId, AzureAd__TenantId, AzureAd__Instance, and AzureAd__ClientCredentials__0__SourceType / AzureAd__ClientCredentials__0__ClientSecret. This is typically a different registration than one used for a plain client-credentials run.

Client discovery

MCP clients can discover the authorization server and scope from GET /.well-known/oauth-protected-resource, which advertises the authorization server ({instance}/{tenantId}/v2.0) and the supported scope ({clientId}/Mcp.Tools.ReadWrite). The WWW-Authenticate challenge on an unauthenticated request points clients here.


Running with Docker

Flowon Logic Conductor ships with a Dockerfile (Alpine-based) for containerised deployments:

# Build a publish image
dotnet publish -c Release

# Or build the Docker image directly, then run it
docker build -t flowon-logic-conductor .
docker run \
-e FLOWON_PROJECTS="Sales" \
-e DATAVERSE_URL="https://yourorg.crm.dynamics.com/" \
-e DATAVERSE_CLIENT_ID="<app-id>" \
-e DATAVERSE_CLIENT_SECRET="<secret>" \
-p 5260:5260 flowon-logic-conductor \
--transport http --disable-http-incoming-auth --dataverse-auth-strategy UseClientCredentials

The container listens on port 5260 by default (override with ASPNETCORE_URLS). Pass whichever environment variables match your chosen strategy — e.g. the AzureAd__* set for UseOnBehalfOf.


Connecting to Your AI Client

Once the server is running, point your AI client's MCP configuration at it.

Stdio Mode

The client launches the server process:

{
"mcpServers": {
"flowon-logic-conductor": {
"command": "dotnet",
"args": [
"run",
"--project", "FlowOn.Xrm.Conductor.Mcp.Server.csproj",
"--",
"--dataverse-auth-strategy", "UseClientCredentials"
],
"env": {
"FLOWON_PROJECTS": "Sales",
"DATAVERSE_URL": "https://yourorg.crm.dynamics.com/",
"DATAVERSE_CLIENT_ID": "<app-id>",
"DATAVERSE_CLIENT_SECRET": "<secret>"
}
}
}
}

HTTP Mode

Point the client at the /mcp endpoint of a running server:

{
"mcpServers": {
"flowon-logic-conductor": {
"url": "https://your-mcp-server-host:port/mcp"
}
}
}

One Instance Per Environment

┌─────────────────────────────────────────────────────────────────────┐
│ ENVIRONMENT ISOLATION PATTERN │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Conductor │ │ Conductor │ │ Conductor │ │
│ │ (Dev) │ │ (UAT) │ │ (Prod) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Dataverse │ │ Dataverse │ │ Dataverse │ │
│ │ Dev Env │ │ UAT Env │ │ Prod Env │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ Each instance exposes the action artifacts of its own │
│ environment, executed under the calling user's identity. │
│ │
└─────────────────────────────────────────────────────────────────────┘

Run a separate Flowon Logic Conductor instance per Dataverse environment so agents only ever invoke the logic deployed to that environment.