TL;DR
Five supported paths, one decision tree. Choosing wrongly here is the most expensive mistake in an ERP AI project, and the choice turns on three questions — does it write, is it analytical, and is it entity CRUD.
MCP server, virtual entities or dual-write — how should an AI agent read Dynamics data?
There are five supported answers and one decision tree, and choosing wrongly here is the most expensive mistake available in an ERP AI project — not because any path is bad, but because the wrong one is discovered late, after the agent works and before anyone notices what it is reading.
8 minute read.
The five paths, side by side
- 1 — Path: Dynamics 365 ERP MCP server
[GA]· Reach: Near-total — entities, forms and X++ actions · Read: Yes · Write: Yes · Latency: Live · Best for: Transactional agents. The default - 2 — Path: AI tools — your own X++ classes · Reach: Exactly what you code · Read: Yes · Write: Yes · Latency: Live · Best for: Complex logic, calculated values, guarded operations
- 3 — Path: ERP Analytics MCP
[PP]· Reach: Business performance analytics models · Read: Yes · Write: No · Latency: Pre-transformed twice daily · Best for: Analysis, ranking, anomaly finding - 4 — Path: Virtual entities in Dataverse
[GA]· Reach: Selected entities · Read: Yes · Write: Yes · Latency: Live pass-through · Best for: Knowledge sources, Power Apps, connectors - 5 — Path: Dual-write to Dataverse tables
[GA]· Reach: Mapped tables · Read: Yes · Write: Yes · Latency: Near real-time sync · Best for: Native Dataverse tables as agent knowledge
Two more exist at the edges and are worth naming: Inventory Visibility [GA] over REST for availability specifically, and the classic OData and custom service endpoints, which still work perfectly well and simply have no agent affordances — no discovery, no metadata negotiation, nothing that helps a model find its way.
The decision tree, which is shorter than the table
Three questions: does it write, is it analytical, is it CRUD. Almost every real scenario resolves in under a minute, and the discipline of answering them in that order is what stops a team defaulting to whatever they used last time.
Inside the default path
Most agents land on the ERP MCP server, so it is worth knowing what "the MCP server" actually means at read time. Three tool families:
- **Data tools** — What it reaches: Entities, through OData or SQL · Cost profile: Fewest calls. The preferred path for CRUD
- **Form tools** — What it reaches: The application's view model — controls, grids, actions · Cost profile: More calls. Necessary when logic lives behind a button
- **Action tools** — What it reaches: X++ classes exposed through the AI tool framework · Cost profile: One call for an operation you defined
One change inside the data family deserves its own paragraph, because it is quiet and consequential. From version 10.0.48, data_find_entities_sql reads through SQL rather than OData, replacing the OData read tool.
That is not a performance tweak. It removes the entity-shape constraint on what an agent can ask for. Under OData reads, a question spanning several entities becomes several calls plus reasoning to stitch them; under SQL, it can be one query. It materially changes what a single call can answer — and it equally changes the security review, because the shape of what a role permits and what a query can join are now different conversations.
Why not just use virtual entities for everything
The honest case for them is strong: an F&O entity appears as a Dataverse table, rows stay in the ERP, Dataverse queries them live through a plugin, and you get full create-read-update-delete rather than read-only. For a Power App, a connector, or a Copilot Studio knowledge source, that is exactly right.
The case against, for a transactional agent, is about fit rather than quality. Microsoft notes that "because a finance and operations entity is directly invoked in all operations, any business logic on the entity or its backing tables is also invoked" — so the latency is what the ERP's logic costs, and Microsoft's instruction is to "always" co-locate the two environments in one Azure region.
Two further constraints. Dataverse caps what a single virtual-table query returns, which rules the path out for anything bulk.
And the service-protection exemption is narrower than it reads: it applies only when Power Platform integration is enabled, and only to the endpoints the plugin invokes. The call still goes through the Dataverse API, where Dataverse's own limits "might still apply".
Use them where they are excellent — surfacing ERP data inside the Power Platform. Do not reach for them as a general agent read path when the MCP server reads the same data with agent affordances built in.
Why not dual-write
Dual-write is synchronous, bidirectional, transactional row replication between the ERP and Dataverse, driven by declarative table maps. When you genuinely need the same record to exist in both systems — customer, product, an order header driving a CRM-led capture flow — nothing else does that job.
For an agent read path it is usually the wrong shape, and the reason is coupling. Dual-write makes your ERP's transaction depend on Dataverse succeeding, including on every plugin that fires there. That is sometimes exactly what you want and frequently not, and it is a large architectural commitment to take on in order to let an agent read something it could have read directly.
Our position: dual-write for master data and lightweight transactional headers where tight coupling is genuinely wanted. Not as an integration bus, and not as an agent's data feed.
The property that holds across every path
Whichever path you choose, the security model does not change shape: the F&O security role of the authenticated identity determines what the agent sees. It is inherited, not re-implemented.
- The ERP MCP server returns only the menu items, entities and APIs that role can reach, and "rejects any explicit calls to actions or objects to which the user role doesn't have access".
- The form view model "includes only data, fields, and actions to which the user role has access".
- The analytics server executes its DAX (Data Analysis Expressions — the Power BI query language) queries "with automatic row-level security enforcement", based on the user's role.
This is genuinely useful in a design review, because it means the read-path decision and the security decision are separable. You are not trading governance for convenience between these options — you are choosing latency, reach and call count.
The special case worth carrying
Availability is not a read-path choice, it is a service. If your scenario is "can we promise this?", Inventory Visibility [GA] is the grounding source: real-time soft reservations posted from any order channel to prevent overselling, and available-to-promise calculated forward, over REST, usable from non-Microsoft channels too.
The pattern is: read availability from Inventory Visibility, act through the MCP server. Two surfaces, each doing the job it exists for.
The counter-argument
"Copy the data into a lake and let the agent read from there. One place, cheap queries, no throttling, no ERP load."
For genuinely analytical work over long histories, that is a reasonable architecture and it is not what this article is arguing against. But as a general agent read path it fails on three counts, and they compound.
Stale by construction. A copy has a refresh cadence, and if the answer changes inside that cadence the agent is confidently wrong.
The ERP's row filtering does not travel with the data. Microsoft's Synapse Link documentation states that the system "applies a bypass for extensible data security policies for the Azure Synapse Link service" — and extensible data security is how finance and operations filters rows by legal entity or site.
On the lake side, OneLake security is a separate deny-by-default role model with its own row-level security, written as SQL predicates. Somebody has to author it, and that somebody is usually not at the ERP end.
It cannot write. Any action still needs one of the paths above, so you have built two integrations where one would have done.
Use a lake for analysis. Do not use it as the way an agent understands the current state of the business.
What to do this week
- For each agent scenario you have, run the three questions in order — writes, analytical, CRUD — and write the answer down. Disagreement in the room is the useful part.
- Check your version. If you are on 10.0.48 or later,
data_find_entities_sqlchanges what a single call can answer and is worth a look before anyone designs around multi-call stitching. - If any agent reads from a copy of ERP data, write down the refresh cadence next to the questions it answers. That comparison is either reassuring or the most important thing you learn this week.
Where we would draw the line
We would not use dual-write to give an agent read access, because the coupling cost is out of all proportion to the benefit when a live read path exists. We would not build an agent read path on a lake copy and describe it as current. And we would not choose virtual entities for a transactional agent purely because the team already knows Dataverse — familiarity is a real consideration and it is not worth a latency profile you cannot fix without moving an environment.
About Cognilium Cognilium is the AI optimization layer for Dynamics 365 — complementary apps that optimize the pricing, inventory, warehouse and planning decisions your ERP manages but can't optimize. Built on Power Platform, Dataverse and Azure. https://cognilium.ai · https://www.linkedin.com/company/37180269/
If you are choosing a read path for a specific agent, we will run the three questions with you on a call and say which one we would pick and why. https://cognilium.ai
Sources
- Dynamics 365 ERP MCP server — tools and reach
- ERP Analytics MCP overview
- Virtual entities overview
- Dual-write overview
- Inventory Visibility
- Integration between finance and operations apps and third-party services
Sources
- learn.microsoft.com — copilot mcp
- learn.microsoft.com — erp analytics mcp overview
- learn.microsoft.com — virtual entities overview
- learn.microsoft.com — limits tshoot virtual tables
- learn.microsoft.com — service protection api limits
- learn.microsoft.com — dual write overview
- learn.microsoft.com — sync limits
- learn.microsoft.com — inventory visibility
- learn.microsoft.com — integration overview
- learn.microsoft.com — azure synapse link select fno data
- learn.microsoft.com — data access control model
Share this article
Muhammad Mudassir
Founder & CEO, Cognilium AI
Muhammad Mudassir
Founder & CEO, Cognilium AI
Mudassir Marwat's argument is that ERP systems record decisions they never optimise.
