Setup and Configuration
Prerequisites
Before running Flowon Logic Assist, ensure the following are in place:
| Requirement | Details |
|---|---|
| .NET Runtime | .NET 10 or later (the server targets net10.0) |
| Logic Composer | Installed and licensed in the target Dataverse environment (the baseline for most tool groups) |
| Process Orchestrator | Optional - required only for the Business Process tools |
| Dataverse Connection | A Dataverse connection string or service-principal credentials for the target environment |
| AI Client | An MCP-compatible AI assistant (Claude, GitHub Copilot, etc.) |
| Microsoft Entra app | Required only for Secure HTTP mode (JWT Bearer / On-Behalf-Of auth) |
Tool groups register conditionally based on the Flowon solutions installed in the connected environment. Logic Composer alone is enough to run Flowon Logic Assist; Process Orchestrator only adds the Business Process tools. Metadata, Data, and Solution tools are always available. See Product Scope.
Host Modes
Flowon Logic Assist runs in one of three host modes, selected by the --transport argument and the incoming-auth flag. The mode determines the transport and how incoming requests are authenticated.
| Mode | When to use | Transport | Incoming auth |
|---|---|---|---|
| Stdio (default) | Local desktop MCP clients | Standard I/O streams | None (local process) |
| HTTP | Dev / testing only | POST /mcp | Disabled (--disable-http-incoming-auth); CORS restricted to localhost |
| Secure HTTP | Production / team-shared | POST /mcp | JWT Bearer (Microsoft Entra ID), with On-Behalf-Of user impersonation |
The HostBuilderFactory selects the mode automatically: --transport Http + --disable-http-incoming-auth → HTTP; --transport Http (without that flag) → Secure HTTP; otherwise → Stdio.
Running the Server
Configuration has two independent axes:
- Transport + incoming auth — the host mode above (
--transport,--disable-http-incoming-auth). - 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
| Argument | Values | Default |
|---|---|---|
--transport | Stdio, Http | Stdio |
--dataverse-auth-strategy | UseHostingEnvironmentIdentity, UseOnBehalfOf, UseClientCredentials, UseUserCredentials | auto |
--disable-http-incoming-auth | flag | false |
Log level is set with the LOG_LEVEL environment variable (Trace … Error, default Information).
Dataverse Authentication Strategies
| Strategy | How the server authenticates to Dataverse | Required environment variables |
|---|---|---|
UseHostingEnvironmentIdentity | The host's managed/ambient identity (like DefaultAzureCredential). All calls use the same identity — ideal for cloud/managed-identity hosting. | DATAVERSE_URL |
UseOnBehalfOf | Exchanges the incoming user's token for a Dataverse token — the server acts as the calling user. HTTP modes only. | DATAVERSE_URL + AzureAd__* |
UseClientCredentials | App-only, using a client id + secret (service principal). | DATAVERSE_URL, DATAVERSE_CLIENT_ID, DATAVERSE_CLIENT_SECRET |
UseUserCredentials | Username + password (on-prem Dynamics). | DYNAMICS_URL, DYNAMICS_APP_ID, DYNAMICS_USER_NAME, DYNAMICS_PASSWORD |
Environment Variables
| Variable | Purpose |
|---|---|
DATAVERSE_URL | Dataverse environment URL (client-credentials, OBO, and hosting-identity strategies) |
DATAVERSE_CLIENT_ID / DATAVERSE_CLIENT_SECRET | Service-principal credentials (UseClientCredentials) |
DYNAMICS_URL / DYNAMICS_APP_ID / DYNAMICS_USER_NAME / DYNAMICS_PASSWORD | On-prem Dynamics credentials (UseUserCredentials) |
AzureAd__ClientId, AzureAd__TenantId, AzureAd__Instance, AzureAd__ClientCredentials__0__SourceType, AzureAd__ClientCredentials__0__ClientSecret | Microsoft Entra app registration — required for incoming JWT auth (Secure HTTP) and the OBO token exchange |
AZURE_CLOUD | Azure sovereign-cloud override |
LOG_LEVEL | Trace, Debug, Information, Warning, Error (default Information) |
ASPNETCORE_URLS | Bind address/port, e.g. http://localhost:1033 |
FLOWON_MCP_COLLECT_TELEMETRY | Set true to emit OpenTelemetry traces/metrics |
FLOWON_MCP_DANGEROUSLY_DISABLE_HTTPS_REDIRECTION | Set true to skip HTTPS redirection (useful behind a reverse proxy) |
ALLOW_INSECURE_EXTERNAL_BINDING | Set true to allow wildcard/external binding in dev HTTP mode |
On-Behalf-Of needs its own app registration. For
UseOnBehalfOf, theAzureAdapp 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)
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 (acts as the calling user)
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
# On-prem Dynamics with user credentials
DYNAMICS_URL="https://dynamics.contoso.com/" \
DYNAMICS_APP_ID="<app-id>" \
DYNAMICS_USER_NAME="DOMAIN\\user" \
DYNAMICS_PASSWORD="<password>" \
dotnet run -- --transport http --disable-http-incoming-auth --dataverse-auth-strategy UseUserCredentials
Endpoints (HTTP modes)
| Endpoint | Description |
|---|---|
POST /mcp | The MCP endpoint. In Secure HTTP mode it requires the McpAccess authorization policy. |
GET /health | Anonymous health check (Secure HTTP mode only). |
GET /.well-known/oauth-protected-resource | OAuth 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 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 query and action.
On-Behalf-Of (OBO)
UseOnBehalfOf is the recommended mode for shared, production deployments. Instead of a single service account, the server acts as the calling user for every Dataverse operation:
- The MCP client calls with the user's access token (
Authorization: Bearer …). - The server validates the Entra JWT and enforces the
McpAccesspolicy — the token must carry the delegated scopeMcp.Tools.ReadWrite(or, for app-only callers, the app permissionMcp.Tools.ReadWrite.All). - 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
tidclaim). - Every Dataverse read/write then runs with the user's own identity — so row-level security, business-unit scoping, and team membership apply exactly as they would in the Dynamics UI.
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 roleMcp.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 Assist ships with a Dockerfile (Alpine-based, linux-x64/linux-arm64) 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-assist .
docker run \
-e DATAVERSE_URL="https://yourorg.crm.dynamics.com/" \
-e DATAVERSE_CLIENT_ID="<app-id>" \
-e DATAVERSE_CLIENT_SECRET="<secret>" \
-p 5260:5260 flowon-logic-assist \
--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. The exact file location and format depend on your client — refer to its documentation.
Stdio Mode
Suitable for local development and desktop AI clients. The client launches the server process:
{
"mcpServers": {
"flowon-logic-assist": {
"command": "dotnet",
"args": [
"run",
"--project", "FlowOn.Xrm.Assist.Mcp.Server.csproj",
"--",
"--dataverse-auth-strategy", "UseClientCredentials"
],
"env": {
"DATAVERSE_URL": "https://yourorg.crm.dynamics.com/",
"DATAVERSE_CLIENT_ID": "<app-id>",
"DATAVERSE_CLIENT_SECRET": "<secret>"
}
}
}
}
HTTP Mode
Suitable for server-hosted deployments and team-shared MCP configurations. Point the client at the /mcp endpoint:
{
"mcpServers": {
"flowon-logic-assist": {
"url": "https://your-mcp-server-host:port/mcp"
}
}
}
Product Scope
Flowon Logic Assist registers tools conditionally, based on which Flowon solutions are installed in the connected Dataverse environment. At startup it always registers the Metadata, Data, Project, and Solution tools, then queries Dataverse for the installed Flowon solutions and enables the matching tool groups:
| Installed solution | Enables |
|---|---|
FlowOnLogic | Logic Block, Logic Flow, Logic Recipe, Configuration, Localized Resource, Service Connection, Schedule, and Event tools |
FlowOnBpm | Business Process tools |
FlowOnApi | API Builder–related tools |
Calling a tool whose product is not installed returns an error. No configuration list is required — availability is derived from the environment itself.
One Instance Per Environment
┌─────────────────────────────────────────────────────────────────────┐
│ ENVIRONMENT ISOLATION PATTERN │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Logic Assist │ │ Logic Assist │ │ Logic Assist │ │
│ │ (Dev) │ │ (UAT) │ │ (Prod) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Dataverse │ │ Dataverse │ │ Dataverse │ │
│ │ Dev Env │ │ UAT Env │ │ Prod Env │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ AI agents connect to the environment-specific instance. │
│ Managed solution protection prevents accidental production edits. │
│ │
└─────────────────────────────────────────────────────────────────────┘
Configure a separate Flowon Logic Assist instance for each Dataverse environment. This ensures AI agents operate only in the intended environment and that Managed Solution Protection guards production correctly.