Lspiguel.Xrm.D365ContextExporter
1.2026.7.2
dotnet add package Lspiguel.Xrm.D365ContextExporter --version 1.2026.7.2
NuGet\Install-Package Lspiguel.Xrm.D365ContextExporter -Version 1.2026.7.2
<PackageReference Include="Lspiguel.Xrm.D365ContextExporter" Version="1.2026.7.2" />
<PackageVersion Include="Lspiguel.Xrm.D365ContextExporter" Version="1.2026.7.2" />
<PackageReference Include="Lspiguel.Xrm.D365ContextExporter" />
paket add Lspiguel.Xrm.D365ContextExporter --version 1.2026.7.2
#r "nuget: Lspiguel.Xrm.D365ContextExporter, 1.2026.7.2"
#:package Lspiguel.Xrm.D365ContextExporter@1.2026.7.2
#addin nuget:?package=Lspiguel.Xrm.D365ContextExporter&version=1.2026.7.2
#tool nuget:?package=Lspiguel.Xrm.D365ContextExporter&version=1.2026.7.2
D365 CE Context Exporter
An XrmToolBox plugin that exports Microsoft Dynamics 365 Customer Engagement (Dataverse) metadata and configuration as Markdown grounding files for use with non-agentic AI assistants (GitHub Copilot, Claude, ChatGPT, etc.).
What it does
Here's something I noticed: not everyone has a full GitHub Copilot, Claude or Cursor license. Not everyone can wire up MCP servers, define custom skills, or point an agent at a live Dataverse environment. But most of us do have access to a web AI agent, or to an enterprise general agent like Microsoft 365 Copilot — and those tools can be genuinely useful, if only they knew what your system actually looks like.
I built something to bridge that gap.
D365 CE Context Exporter is a free XrmToolBox plugin that connects to your Dataverse environment, runs a set of queries, and generates a structured Markdown file. You upload that file to your AI assistant of choice, and suddenly it knows your entities, your attributes, your security roles, your solution structure.
No need to spend time on every chat explaining what a contact record means in your org, how it's different from the out of the box contact.
It includes 6 configurations ("specs") — entity dictionary, security model, forms & views, option sets, solution inventory — and if those don't cover what you need, the templates are plain text files you can edit yourself without touching any code.
Runs entirely inside XrmToolBox.
I'd love to hear from others in the D365 / Power Platform space — what metadata would you most want to export as AI grounding context? Always looking for ideas on what to add next.
👉 Search for "D365ContextExporter" on the XrmToolBox Tool Library.<br> 👉 https://github.com/lspiguel/ai-tooling
#Dynamics365 #Dataverse #XrmToolBox #AIAssistants #PowerPlatform #OpenSource
Prerequisites
| Requirement | Version |
|---|---|
| XrmToolBox | 1.2025.x or later |
| .NET Framework | 4.8 |
Quickstart
The plugin connects to your Dataverse environment, runs a set of FetchXML and Web API queries defined in a spec configuration file, serialises the results to an intermediate JSON file, and renders a structured Markdown document using an in-process Scriban template. The resulting .context.md file is ready to upload to your AI assistant as grounding context.
- Install the plugin — open XrmToolBox, go to Tool Library, search for D365 CE Context Exporter, and install.
- Connect — connect XrmToolBox to your Dataverse environment.
- Pick a base directory — click the folder picker and choose (or create) an empty folder. On first use the plugin will offer to deploy the reference configuration there.
- Run first-time setup — accept the prompt to deploy sample specs, FetchXML queries, and Scriban templates to the folder.
- Select a spec — choose one of the available specs from the dropdown (six sample specs are provided out of the box).
- Click Run — the plugin executes all queries, renders the template, and places the output in
output\<SpecName>.context.md. - Upload — attach or paste the
.context.mdfile into your AI assistant conversation as grounding context.
Sample specs
Six specs are deployed on first-time setup:
| Spec | What it captures |
|---|---|
EntityDictionary |
All entity definitions with their attributes |
SecurityModel |
Security roles and privilege depths |
SolutionsReference |
Solution hierarchy and components |
FormsAndViews |
Entity forms and views |
Optionsets |
Global option sets |
SolutionInventory |
Solutions, plugins, flows, environment variables, custom APIs |
Folder structure
After first-time setup your base directory will look like this:
Context-Exporter/
├── config/
│ ├── queries/ FetchXML query files
│ │ ├── solutions-detail.fetch.xml
│ │ ├── security-roles.fetch.xml
│ │ └── ...
│ ├── transformations/ Scriban templates (.sbn)
│ │ ├── entity-dictionary.sbn
│ │ ├── forms-and-views.sbn
│ │ ├── optionsets.sbn
│ │ ├── security-model.sbn
│ │ ├── solution-inventory.sbn
│ │ └── solutions-reference.sbn
│ ├── EntityDictionary.context-exporter-config.json
│ ├── FormsAndViews.context-exporter-config.json
│ ├── Optionsets.context-exporter-config.json
│ ├── SecurityModel.context-exporter-config.json
│ ├── SolutionInventory.context-exporter-config.json
│ └── SolutionsReference.context-exporter-config.json
├── output/ Rendered grounding files (git-ignored)
│ └── EntityDictionary.context.md
├── runs/ Per-run working directories (git-ignored)
│ └── 20250501-120000/
│ ├── intermediate.json
│ └── output.md
├── LEGAL.md Legal notice prepended to all outputs
└── version.txt Plugin version that last deployed this config
Plugin upgrades
When the plugin detects that its version differs from the version.txt in your base directory, it offers to redeploy the reference configuration (queries, templates, and sample specs). Your LEGAL.md and any custom files are never overwritten during an upgrade.
Configuration reference
Each spec is a *.context-exporter-config.json file in config/.
| Field | Type | Required | Description |
|---|---|---|---|
spec |
string | Yes | Spec name; becomes the output filename stem. |
version |
string | No | Config schema version (default "1.0.0"). |
transformation |
string | Yes | Filename of the Scriban template in config/transformations/. |
legal |
string | No | Path to a LEGAL.md file (relative to base dir) prepended to the output. |
output.attributeDenyList |
string[] | No | Attribute name substrings to exclude from output. |
frontMatter |
object | No | Key/value pairs injected as YAML front-matter. |
queries |
array | Yes | Ordered list of query definitions (see below). |
python |
object | No | Ignored. Retained for compatibility with existing config files. |
Query definition fields
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Unique identifier; used as the per-query intermediate filename. |
type |
string | Yes | "fetchxml", "webapi", or "metadata". |
resultKey |
string | Yes | Key name in intermediate.json; referenced in templates. |
source |
string | fetchxml only | Filename of the FetchXML file in config/queries/. |
path |
string | webapi only | OData path appended to the environment URL. |
select |
string[] | No | OData field names appended as $select=… to a webapi path. |
metadataTarget |
string | metadata only | One of entities, attributes, optionsets, relationships. |
maxRecords |
integer | No | Maximum records to retrieve. |
Authoring templates
Templates use the Scriban template language (.sbn extension). Each resultKey from your spec is available as a top-level variable in the template.
- Create a new
.sbnfile inconfig/transformations/(or copy an existing one as a starting point). - Write your template using Scriban syntax. The
resultKeyvalues from your spec are the top-level objects. - Use any of the built-in functions listed below.
- Add a new spec config in
config/pointing to your new template.
Do not use
object.from_jsonorobject.to_jsonin templates. The plugin embeds Scriban with its System.Text.Json support compiled out (SCRIBAN_NO_SYSTEM_TEXT_JSON), so these two built-ins throw a runtime error if a template calls them. This is deliberate: shipping a privateSystem.Text.Json.dllalongside the plugin caused XrmToolBox to lock the file, which broke updating and uninstalling the tool from the Tool Library ("The process cannot access the file … because it is being used by another process"). You should not need them anyway — query results are already parsed and available as template variables, so there is no JSON left to deserialise by the time a template runs.
Built-in template functions
The following functions are available in all templates:
| Function | Signature | Description |
|---|---|---|
schemaname_to_title |
(name) |
Converts a schema name like MyCustomField to My Custom Field. |
display_label |
(labelObj, fallback) |
Extracts the user-localised label string from a Dataverse DisplayName object. |
markdown_table |
(rows, columns) |
Renders a Markdown table from an array of objects and a column list. |
csv_list |
(items, attr) |
Joins an array into a comma-separated string, optionally extracting a named attribute. |
pluck |
(items, key) |
Returns a deduplicated array of a single attribute extracted from each item. |
group_by_key |
(items, key) |
Groups an array by a key; returns [{key, items}]. |
optionset_label |
(options, value) |
Resolves an option set integer value to its localised label. |
attr_type_abbrev |
(type) |
Abbreviates a Dataverse attribute type string (e.g. Lookup → lkp). |
req_indicator |
(requiredLevel) |
Returns **R** for Required, r for Recommended, - otherwise. |
iso_date |
(dateString) |
Truncates a date-time string to yyyy-MM-dd. |
component_type_name |
(code) |
Resolves a solution component type code to a human-readable name. |
format_forms |
(forms) |
Formats a list of form objects as Name(type), …. |
format_views |
(views) |
Formats a list of view objects as a comma-separated name list. |
entity_forms |
(forms, entityLogicalName) |
Filters a form array to those belonging to the given entity. |
entity_views |
(views, entityLogicalName) |
Filters a view array to those belonging to the given entity. |
plugin_stage |
(code) |
Resolves a plugin stage integer (10/20/40/45) to PreVal, Pre, or Post. |
plugin_mode |
(code) |
Resolves a plugin mode integer (0/1) to Sync or Async. |
flow_trigger |
(name) |
Infers the trigger type of a cloud flow from its name (HTTP, Sched, Child, Manual, Auto). |
classic_trigger |
(workflow) |
Returns the trigger string for a classic workflow object (Create/Update/Delete). |
envvar_type |
(code) |
Resolves an environment variable type integer to its type name. |
api_param_type |
(code) |
Resolves a custom API parameter type integer to a short type string. |
priv_depth |
(code) |
Resolves a privilege depth integer to a human-readable depth name. |
Building from source
dotnet restore tooling/D365ContextExporter/D365ContextExporter.sln
dotnet build tooling/D365ContextExporter/D365ContextExporter.sln --configuration Release
dotnet test tooling/D365ContextExporter/D365ContextExporter.Tests/D365ContextExporter.Tests.csproj
For local development, copy the DLL to your XrmToolBox Plugins folder. See Directory.Build.targets.example for a template that automates this on build.
License
MIT — see LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET Framework | net472 is compatible. net48 was computed. net481 was computed. |
-
- XrmToolBox (>= 1.2025.10.74)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 1.2026.7.2 | 385 | 7/27/2026 | |
| 1.2026.7.1 | 184 | 7/15/2026 | |
| 1.2026.6.1 | 230 | 6/12/2026 | |
| 0.2026.0.7 | 178 | 5/28/2026 | |
| 0.2026.0.5 | 169 | 5/9/2026 |
IMPORTANT: Tool Library could not update or uninstall this tool, failing with
"An error occured while copying files: The process cannot access the file
'...\Plugins\D365ContextExporter\System.Text.Json.dll' because it is being
used by another process."
FIX - one-time manual cleanup when upgrading from an older version.
Because the old files are locked and XrmToolBox never removes them, this
upgrade may fail with the same error one last time. To fix:
1. Close ALL XrmToolBox windows (check Task Manager for leftover
XrmToolBox.exe processes).
2. Open File Explorer and go to %AppData%\MscrmTools\XrmToolBox\Plugins
3. Delete the D365ContextExporter folder (it contains the old
System.Text.Json.dll and System.Text.Encodings.Web.dll).
4. If the upgrade previously failed halfway, also delete
D365ContextExporter.dll and D365ContextExporter.pdb from the Plugins
folder itself.
5. Start XrmToolBox and install/update the tool from the Tool Library.
CAUSE: previous versions shipped System.Text.Json.dll and
System.Text.Encodings.Web.dll as loose files in a Plugins subfolder.
XrmToolBox locks every DLL found in Plugins subfolders shortly after
start-up (even if the tool is never opened), so any later attempt by the
Tool Library to overwrite or delete those files fails. This version ships
no loose dependency DLLs at all, so updates and uninstalls work normally
from now on.