xrm-mcp
Read and carefully write Microsoft Dataverse/XRM data from an AI coding agent over the Dataverse Web API.
Connectivity:
pingverifies auth/connectivity and returns org/user/tenant details.Discover tables:
find_tablesearches by display/partial logical name;list_tableslists custom Dataverse tables with optional search, prefix, and Microsoft-prefix filters.Inspect schema:
describe_tablereturns columns, types, and descriptions.Query records:
query_recordsretrieves records with OData$select,$filter,$orderby, and up to 5,000 results.Create records:
create_recordinserts a single record.Update records:
update_recordchanges specific fields on an existing record.Upsert records:
upsert_recordcreates or updates by alternate key for sync/import scenarios.Auth: Uses Azure CLI first, falls back to MSAL device flow; caches tokens and per-
org_urlidentities for multi-tenant use.Environment access: Works with any Dataverse environment via
org_urlper call; no Power Platform admin setup, Managed Environments, or Copilot Credits.
Provides read and write access to Microsoft Dataverse environments, enabling GitHub Copilot to query tables, describe schemas, and create, update, or upsert records via the Dataverse Web API.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@xrm-mcp Show me all contacts from myorg.crm4.dynamics.com created this week"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
xrm-mcp
A minimal MCP server that gives AI coding agents (Claude Code, GitHub Copilot, Codex CLI, Cursor, Gemini CLI) clean read + careful write access to Microsoft Dataverse / XRM environments via the Dataverse Web API v9.2.
Why this exists: Microsoft ships its own Dataverse MCP server, but it requires Power Platform admin setup, Managed Environments, and Copilot Credits per call.
xrm-mcpis a drop-in alternative that works with any Dataverse environment using your existing Azure CLI or Microsoft account. Read more →
Features
No Microsoft MCP billing — calls the Dataverse Web API directly, no Copilot Credits consumed
No admin toggles — works with any Dataverse environment you can log into
No Managed Environment required — standard environments work fine
No per-environment setup — org_url is a parameter on every tool call
Multi-tenant by design — connect to multiple orgs in the same session, with per-environment identity caching so switching between tenants doesn't require re-authenticating each time
Azure CLI + MSAL auth — tries
azfirst, falls back to interactive device flow8 MCP tools — ping, find/list tables, describe schema, query, create, update, upsert
Related MCP server: dataverse-mcp-server
Installation
For uv, pipx, virtual environments, pinned tags, and client setup, see the installation guide.
Install via pipx (recommended):
pipx install git+https://github.com/jukkan/xrm-mcp.gitOr via pip:
pip install git+https://github.com/jukkan/xrm-mcp.gitUsage
Configuring your AI agent
Add xrm-mcp to your agent's MCP configuration.
Claude Desktop / Claude Code (~/.claude/claude_desktop_config.json or .mcp.json):
{
"mcpServers": {
"xrm-mcp": {
"command": "xrm-mcp"
}
}
}GitHub Copilot (VS Code) — add to .vscode/mcp.json in your workspace:
{
"servers": {
"xrm-mcp": {
"type": "stdio",
"command": "xrm-mcp"
}
}
}Once configured, pass your environment URL with every request and the agent takes it from there:
"Show me all project records from https://myorg.crm4.dynamics.com created in the last 30 days"
Running the server manually
xrm-mcpThe server uses FastMCP and communicates over stdin/stdout (stdio transport).
Authentication
XRM MCP attempts authentication in the following order:
Azure CLI — if
azis available and logged inMSAL device flow — interactive browser-based login
Tokens are cached at ~/.xrm-mcp/cache.json.
If you work across multiple tenants (e.g. your own production environment, demo
environments, and customer tenants), XRM MCP remembers which identity last
worked for each org_url in ~/.xrm-mcp/identity_cache.json and prefers it on
the next call — so switching tenants doesn't depend on which az account
happens to be active. If a call gets a 401/403, that org's cached identity
is cleared automatically and the error message tells you to just retry, which
re-discovers a working identity.
To re-authenticate, delete ~/.xrm-mcp/cache.json or use az login. To reset
which identity is used for a specific org, delete its entry from
~/.xrm-mcp/identity_cache.json.
Testing authentication manually
python -m xrm_mcp.auth https://yourorg.crm4.dynamics.comMCP Tools
Read Tools
ping(org_url)
Verify connectivity and authentication to a Dataverse environment
Returns: status, org_url, user_id, business_unit_id, org_id, auth_method, tenant_id
Call this first when connecting to a new environment;
auth_method/tenant_idlet you confirm which identity answered the call
find_table(org_url, name)
Search for a table by display name or partial logical name
Use when the user says "hour entries" and you need the exact logical name
Returns all matching tables sorted by exact display name match first
list_tables(org_url, search="", custom_only=True, prefix="", exclude_ms_prefixes=True)
List Dataverse tables, defaulting to custom entities only
custom_only=True— only return custom entities (default)prefix="na_"— filter to a specific publisher prefixexclude_ms_prefixes=False— include Microsoft solution tables (msdyn_, adx_, etc.)Returns: logical_name, display_name, entity_set_name, is_custom, description
describe_table(org_url, table)
Get columns, types and descriptions for a Dataverse table
Call this before querying when you need exact column names for $select or $filter
Returns: table_name, columns with metadata
query_records(org_url, table, select="", filter="", top=100, orderby="")
Query records from a table using OData filter syntax
Returns: {count, records}
Top is capped at 5000
selectis validated against real column names before querying; an invalid column raises a clear error naming it, instead of silently returning every column
Write Tools
create_record(org_url, table, data)
Create a single record
Returns: {id}
update_record(org_url, table, record_id, data)
Update specific fields on an existing record
Returns: {success, id}
upsert_record(org_url, table, alternate_key, alternate_value, data)
Create or update a record using an alternate key (for sync/import scenarios)
Returns: {success, alternate_key, alternate_value}
Example Usage
See CLAUDE.md for detailed agent usage examples and WHY.md for how this compares to Microsoft's own Dataverse MCP server.
Requirements
Python 3.10+
Azure CLI (optional, for
azauthentication)Access to a Dataverse / Dynamics 365 environment
Dependencies
fastmcp >= 3.0, < 4
msal >= 1.28.0, < 2
httpx >= 0.27.0, < 1
Version 0.2.0 moved from FastMCP 2.x to FastMCP 3.x. Existing installs need to
be reinstalled (for example pipx reinstall xrm-mcp or
uv tool install --force ...) so the new FastMCP version is resolved.
Development
Clone the repository:
git clone https://github.com/jukkan/xrm-mcp.git
cd xrm-mcpInstall in development mode:
pip install -e ".[dev]"Run the tests (no Dataverse environment or credentials required):
pytestLicense
MIT
Contributing
Contributions welcome! Please open an issue or pull request.
Available Tools
8 toolscreate_recordC
Create a single record in an XRM table.
Inputs: data (required), table (required), org_url (required). Returns: object
describe_tableA
Get columns, types and descriptions for an XRM table.
Call this before querying when you need to know column names for $select or $filter.
Inputs: table (required), org_url (required). Returns: object
find_tableA
Search for a table by display name or partial logical name.
Use this when the user gives a friendly name like 'hour entry' or 'hours' and you don't know the exact logical name. Returns all candidate matches from this specific environment — do not use workspace files or project notes to infer table names.
Inputs: name (required), org_url (required). Returns: result
list_tablesA
Lists Dataverse tables. Defaults to custom tables only, excluding Microsoft-prefixed solution tables (msdyn_, msfp_, adx_ etc).
Use prefix='na_' to filter to a specific publisher. Use exclude_ms_prefixes=False to see all custom tables.
Inputs: org_url (required), prefix, search, custom_only, +1 more. Returns: result
pingA
Test connectivity to an XRM/Dataverse environment and verify authentication.
Call this first to verify your setup and connection to the Dataverse environment.
Inputs: org_url (required). Returns: object
query_recordsA
Query records from an XRM/Dataverse table.
Inputs: table (required), org_url (required), top, filter, +2 more. Returns: object
update_recordB
Update fields on a single existing XRM record.
Inputs: data (required), table (required), org_url (required), record_id (required). Returns: object
upsert_recordA
Create or update a record matched by an alternate key column.
Use this for sync/import scenarios where you don't have the record GUID.
Inputs: data (required), table (required), org_url (required), alternate_key (required), +1 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 8 tools
Each tool targets a distinct operation (CRUD, metadata queries, connectivity test) with no functional overlap, making it easy for an agent to select the correct one.
Most tools follow a clear verb_noun pattern (create_record, query_records, etc.), but ping uses a single verb, which is a minor inconsistency.
The tool count of 8 is well-scoped for a Dataverse MCP server, covering essential operations without unnecessary bloat.
The tool set covers creation, update, query, and metadata, but lacks a delete_record tool and a direct get-by-ID tool, which may cause agent failures in typical workflows.
Maintenance
Related MCP Connectors
MCP server that lets AI assistants use all OneSchema features exposed via the public API.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
Hosted MCP server for AI-driven data ops. Create apps, manage schemas, and CRUD structured data.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceThe most complete MCP server for Microsoft Dataverse.218 npm18MIT
- AlicenseBqualityBmaintenanceMCP server for Microsoft Dataverse API with safe-by-default configuration. Works with any Dataverse / Dynamics 365 environment.23228 npm8MIT
- AlicenseNot gradedqualityDmaintenanceA self-hosted MCP server that enables AI assistants to inspect and manage Microsoft Power Automate cloud flows and Dataverse records locally, using your own Azure identity.MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server for OData v4 endpoints, especially Microsoft Dataverse/Dynamics 365, enabling authentication, schema discovery, querying, CRUD, and more via natural language.MIT