An MCP server for interacting with Microsoft Dataverse environments during development
Project description
Dataverse MCP Server
An MCP server for interacting with Microsoft Dataverse environments. Built with FastMCP and the official PowerPlatform-Dataverse-Client Python SDK.
Features
- Solution inspection — list solutions, get solution details, browse solution components
- Table querying — flexible OData-style queries against any Dataverse table
- Record management — create, update, and delete records with safety guards
- Record associations — associate and disassociate records via navigation properties
- Schema exploration — list tables, inspect table and column metadata, browse relationships, choice columns, and global choices
- Table schema management — create, update, and delete custom tables, columns, relationships, and choices; gated by
DATAVERSE_ALLOW_WRITE/DATAVERSE_ALLOW_DELETEenv vars - Security inspection — retrieve user privileges and check principal access rights on records
- Environment discovery — list Power Platform environments available to the authenticated user
- Multi-environment targeting — one MCP server config can query any Dataverse org the caller specifies
- Agent-friendly — rich tool descriptions designed for AI agent discoverability
- Secure — Pydantic v2 input validation, GUID format enforcement, OData injection prevention
Prerequisites
- uv — install from docs.astral.sh/uv
- Access to a Microsoft Dataverse environment
- Azure CLI (
az login) for authentication, or useinteractivefor browser-based sign-in
Installation
You can run this server either from PyPI with uvx or directly from a local checkout.
Option 1: Run from PyPI
uvx dataverse-mcp
uvx downloads and runs the package in an isolated environment.
Option 2: Run from a local checkout
git clone https://github.com/ryanmichaeljames/dataverse-mcp.git
cd dataverse-mcp
uv sync
This creates .venv, which is the local Python environment used by the source-based MCP configuration shown below.
Configuration
Configure the server through your MCP client. In VS Code, that means the env
block on the server entry in .vscode/mcp.json or your user mcp.json.
This project does not use a .env file for normal setup.
| Variable | Required | Default | Description |
|---|---|---|---|
DATAVERSE_URL |
No | — | Optional fallback org URL, set only if you want requests without dataverse_url to still work |
DATAVERSE_AUTH_TYPE |
No | azure_cli |
Auth method: interactive or azure_cli |
DATAVERSE_ALLOW_WRITE |
No | false |
Set to true to enable create, update, and mutation tools |
DATAVERSE_ALLOW_DELETE |
No | false |
Set to true to enable delete and disassociate tools |
Authentication Methods
azure_cli(default) — Uses your existingaz loginsession. Best for local development.interactive— Opens a browser window for interactive sign-in.
Usage
This server communicates over stdio and works with any MCP-compatible client.
VS Code
Add the server to your VS Code MCP configuration. Choose either the packaged uvx form or the local source form.
Run from PyPI:
{
"servers": {
"dataverse-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["dataverse-mcp"],
"env": {
"DATAVERSE_AUTH_TYPE": "azure_cli"
}
}
}
}
Run from a local checkout on the same machine:
{
"servers": {
"dataverse-mcp-local": {
"type": "stdio",
"command": "C:\\path\\to\\dataverse-mcp\\.venv\\Scripts\\python.exe",
"args": ["-m", "dataverse_mcp.server"],
"env": {
"PYTHONPATH": "C:\\path\\to\\dataverse-mcp\\src",
"DATAVERSE_AUTH_TYPE": "azure_cli"
}
}
}
}
The local source form does not require a build step. Code changes are picked up on the next server start.
If you want a fallback environment for requests that omit dataverse_url, add
DATAVERSE_URL to that same env block. Keep it in MCP config, not a .env
file.
Environment Targeting
Use a single server entry and provide dataverse_url on each tool call to target the Dataverse environment explicitly. Example tool input:
{
"dataverse_url": "https://yourorg.crm.dynamics.com",
"table_name": "account",
"select": ["name", "accountid"],
"top": 10
}
If you omit dataverse_url, the server falls back to DATAVERSE_URL when that value is configured in your MCP server env. That fallback is kept for backward compatibility only; the preferred setup is explicit environment targeting on every request.
Use dataverse_list_environments first if you need to discover which Power Platform environments are available before choosing a dataverse_url.
dataverse_list_environments does not require dataverse_url and always returns the full normalized environment payload. Optional flags let you include capacity and add-on details.
Safety Guards
Write and delete tools are disabled by default and must be explicitly enabled via environment variables in your MCP config. When disabled, those tools are not registered and will not appear to the agent at all.
| Environment Variable | Default | Controls |
|---|---|---|
DATAVERSE_ALLOW_WRITE |
false |
Create, update, associate, merge, and batch mutation tools |
DATAVERSE_ALLOW_DELETE |
false |
Delete and disassociate tools |
Set them in the env block of your MCP server entry:
{
"servers": {
"dataverse-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["dataverse-mcp"],
"env": {
"DATAVERSE_AUTH_TYPE": "azure_cli",
"DATAVERSE_ALLOW_WRITE": "true",
"DATAVERSE_ALLOW_DELETE": "true"
}
}
}
}
You can enable each flag independently — for example, set only DATAVERSE_ALLOW_WRITE=true to allow creates and updates while keeping deletes disabled.
Tools
Tools are grouped by the env var required to enable them. Read-only tools are always available.
Always available (read-only)
| Tool | Description |
|---|---|
dataverse_list_environments |
List Power Platform environments available to the authenticated user via the admin API, returning the full normalized payload |
dataverse_whoami |
Return the authenticated user's UserId, BusinessUnitId, and OrganizationId from the WhoAmI endpoint |
dataverse_get_entity_sets |
List all OData EntitySet names from the service document — discover the correct collection URL for any table |
dataverse_retrieve_user_privileges |
List all security privileges assigned to a system user via their role memberships |
dataverse_retrieve_principal_access |
Check the access rights a user has to a specific record (ReadAccess, WriteAccess, DeleteAccess, etc.) |
dataverse_list_solutions |
List solutions with optional OData filter, select, and top |
dataverse_get_solution |
Get a single solution by unique name or GUID |
dataverse_list_solution_components |
List components in a solution with optional type filter |
dataverse_query_table |
Query records from any table with filter, select, orderby, expand, top |
dataverse_get_record |
Get a single record by table name and GUID |
dataverse_execute_batch |
Execute GET-only $batch queries (up to 1,000 operations); batch requests with mutations require DATAVERSE_ALLOW_WRITE=true |
dataverse_list_tables |
List available tables/entities with optional filter |
dataverse_get_table_metadata |
Get schema details for a specific table |
dataverse_list_columns |
List all column definitions for a table with optional type filter and field selection |
dataverse_get_column |
Get full metadata for a single column including type-specific properties (MaxLength, Precision, RequiredLevel, Format) |
dataverse_list_choice_column_options |
Get all option values (integer code + label) for a Picklist or MultiSelectPicklist column |
dataverse_list_relationships |
List relationship definitions for a table (1:N, N:1, N:N) or all relationships in the environment |
dataverse_get_relationship |
Get full metadata for a single relationship by schema name, including cascade config and navigation property names |
dataverse_check_relationship_eligibility |
Check whether a table can participate in a relationship (referenced, referencing, or many-to-many) via Dataverse eligibility endpoints (CanBeReferenced, CanBeReferencing, CanManyToMany) |
dataverse_list_choices |
List all global choice (option set) definitions in the environment |
dataverse_get_choice |
Get a specific global choice by name or MetadataId, including all option values and labels |
Requires DATAVERSE_ALLOW_WRITE=true
These tools are only registered when DATAVERSE_ALLOW_WRITE=true is set in the MCP server env.
| Tool | Description |
|---|---|
dataverse_associate_records |
Associate two records via a collection-valued navigation property ($ref) |
dataverse_merge_records |
Merge a subordinate record into a target record (account, contact, lead, incident); subordinate is deactivated after merge |
dataverse_create_table |
Create a new custom table with display names, ownership type, and primary name attribute |
dataverse_update_table |
Update an existing table's display name or description |
dataverse_create_column |
Add a new column to a table with typed attribute metadata and display name |
dataverse_update_column |
Update an existing column via full PUT replacement; fetch current definition with dataverse_get_column first |
dataverse_create_one_to_many_relationship |
Create a 1:N relationship and its lookup column on the referencing table |
dataverse_create_many_to_many_relationship |
Create an N:N relationship and its intersect (junction) table |
dataverse_create_multi_table_lookup |
Create a polymorphic lookup column that references multiple tables |
dataverse_update_relationship |
Update an existing relationship via full PUT; fetch current definition with dataverse_get_relationship first |
dataverse_create_choice |
Create a new global choice with initial options |
dataverse_update_choice |
Update an existing global choice via full PUT; fetch current definition with dataverse_get_choice first |
dataverse_add_choice_option |
Add a new option to a global or local choice |
dataverse_update_choice_option |
Update the display label of an existing option in a global or local choice |
dataverse_reorder_choice_options |
Reorder all options of a global or local choice |
dataverse_publish_customizations |
Publish schema changes (tables, choices, relationships) via PublishXml or all unpublished changes via PublishAllXml |
Requires DATAVERSE_ALLOW_DELETE=true
These tools are only registered when DATAVERSE_ALLOW_DELETE=true is set in the MCP server env.
| Tool | Description |
|---|---|
dataverse_disassociate_records |
Remove an association between two records via a navigation property |
dataverse_delete_table |
Permanently delete a custom table and all its data |
dataverse_delete_column |
Permanently delete a custom column and all its data from a table |
dataverse_delete_relationship |
Delete a custom relationship by MetadataId |
dataverse_delete_choice |
Delete a global choice by logical name; ensure no columns reference it first |
dataverse_delete_choice_option |
Remove a specific option value from a global or local choice |
Project Structure
src/dataverse_mcp/
├── __init__.py # Package init
├── _app.py # FastMCP instance (avoids circular imports)
├── server.py # Entry point, logging setup, tool registration
├── client.py # DataverseClient wrapper (auth, lifecycle)
├── models.py # Pydantic v2 input models for all tools
└── tools/
├── __init__.py # Tools package init
├── environments.py # Power Platform environment discovery tool
├── solutions.py # Solution query tools
├── tables.py # Table record query tools
└── metadata.py # Table/column metadata tools
Development
# Install dependencies into .venv
uv sync
# Run the MCP inspector for testing
uv run mcp dev src/dataverse_mcp/server.py
# Run the server directly from source
uv run python -m dataverse_mcp.server
# Compile check touched modules
uv run python -m py_compile src/dataverse_mcp/server.py
If you run the server from a local checkout in VS Code, restart the MCP server after code changes so the new Python source is loaded.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dataverse_mcp-1.3.0.tar.gz.
File metadata
- Download URL: dataverse_mcp-1.3.0.tar.gz
- Upload date:
- Size: 41.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cc2055e2aff1932ccd626483cb755a8078cab5c4291fd641b117b9bad806058
|
|
| MD5 |
ab3b51776a454e78f2321c520f785de8
|
|
| BLAKE2b-256 |
321475a7757f6fd6f13d080ad2acc1e0bf7371c739807c588155aa7c02b60811
|
Provenance
The following attestation bundles were made for dataverse_mcp-1.3.0.tar.gz:
Publisher:
release.yml on ryanmichaeljames/dataverse-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dataverse_mcp-1.3.0.tar.gz -
Subject digest:
1cc2055e2aff1932ccd626483cb755a8078cab5c4291fd641b117b9bad806058 - Sigstore transparency entry: 1501525936
- Sigstore integration time:
-
Permalink:
ryanmichaeljames/dataverse-mcp@bdd60cc77c5b3734bea97177b98fc978dbd79856 -
Branch / Tag:
refs/tags/v1.3.0 - Owner: https://github.com/ryanmichaeljames
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bdd60cc77c5b3734bea97177b98fc978dbd79856 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dataverse_mcp-1.3.0-py3-none-any.whl.
File metadata
- Download URL: dataverse_mcp-1.3.0-py3-none-any.whl
- Upload date:
- Size: 42.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e860b7f1b53ac01980c8cfb59f0a1c7be3c695c85d258553524a1cf44b9a4005
|
|
| MD5 |
ef830d1b5cc5f521010d66b1f0c674d8
|
|
| BLAKE2b-256 |
3af278a715a87e01f55844925bd5adb9a9b416c4a56462f71f00bcc9b7e0347c
|
Provenance
The following attestation bundles were made for dataverse_mcp-1.3.0-py3-none-any.whl:
Publisher:
release.yml on ryanmichaeljames/dataverse-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dataverse_mcp-1.3.0-py3-none-any.whl -
Subject digest:
e860b7f1b53ac01980c8cfb59f0a1c7be3c695c85d258553524a1cf44b9a4005 - Sigstore transparency entry: 1501526116
- Sigstore integration time:
-
Permalink:
ryanmichaeljames/dataverse-mcp@bdd60cc77c5b3734bea97177b98fc978dbd79856 -
Branch / Tag:
refs/tags/v1.3.0 - Owner: https://github.com/ryanmichaeljames
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bdd60cc77c5b3734bea97177b98fc978dbd79856 -
Trigger Event:
push
-
Statement type: