The 2026 pattern for this is the "AI tool" (Microsoft's word for it — you'll also hear "AI plugin"). You write a normal X++ class, deploy it, and decorate it with a couple of attributes. AIPluginOperationAttribute marks the class as something an agent is allowed to call. CustomAPIAttribute ties it to a Dataverse Custom API. Your inputs and outputs are just data contract members with plain-language descriptions:
X
[CustomAPIRequestParameter('The customer account number', true),
DataMember('accountNumber')]
public CustAccount parmAccountNum(CustAccount _accountNum = accountNum)
That description string is the part I want you to notice. It's not a comment — the orchestrator actually reads it to decide when to call your action and how to fill the parameter from someone's messy sentence. You're basically writing prompt hints in your method signatures now. Weird. Kind of great.
Here's the shift. These are headless operations — no form context, no client. Once your class is deployed with the right menu-item security, the Dynamics 365 ERP MCP server picks it up automatically through its find_actions / invoke_action tools. Same code, reachable from the in-app sidecar, from a custom Copilot Studio agent, or from any agent speaking MCP. You write the logic once; the surface area is enormous.
The honest catch: it's still preview, you need the unified developer environment, and there's Dataverse plumbing (the Custom API, request params, response props) plus the classic flush the cache with SysFlushAOD or nothing works gotcha that cost me twenty minutes.
My takeaway: stop thinking of your X++ classes as things only a form can call. Pick one small, useful calculation you already trust — a balance, an eligibility check, a status lookup — wrap it as an AI tool, and let Copilot reach it. It's the most direct line I've found from "code I already have" to "AI that does something real."
The 2026 pattern for this is the "AI tool" (Microsoft's word for it — you'll also hear "AI plugin"). You write a normal X++ class, deploy it, and decorate it with a couple of attributes. AIPluginOperationAttribute marks the class as something an agent is allowed to call. CustomAPIAttribute ties it to a Dataverse Custom API. Your inputs and outputs are just data contract members with plain-language descriptions:
X
[CustomAPIRequestParameter('The customer account number', true),
DataMember('accountNumber')]
public CustAccount parmAccountNum(CustAccount _accountNum = accountNum)
That description string is the part I want you to notice. It's not a comment — the orchestrator actually reads it to decide when to call your action and how to fill the parameter from someone's messy sentence. You're basically writing prompt hints in your method signatures now. Weird. Kind of great.
Here's the shift. These are headless operations — no form context, no client. Once your class is deployed with the right menu-item security, the Dynamics 365 ERP MCP server picks it up automatically through its find_actions / invoke_action tools. Same code, reachable from the in-app sidecar, from a custom Copilot Studio agent, or from any agent speaking MCP. You write the logic once; the surface area is enormous.
The honest catch: it's still preview, you need the unified developer environment, and there's Dataverse plumbing (the Custom API, request params, response props) plus the classic flush the cache with SysFlushAOD or nothing works gotcha that cost me twenty minutes.
My takeaway: stop thinking of your X++ classes as things only a form can call. Pick one small, useful calculation you already trust — a balance, an eligibility check, a status lookup — wrap it as an AI tool, and let Copilot reach it. It's the most direct line I've found from "code I already have" to "AI that does something real."
No comments yet. Be the first to comment!