Overview
Installation
Content Details
Alternatives
What is Dataverse MCP Server?
Dataverse MCP Server is a middleware service specifically designed for Microsoft Dataverse. It allows developers to easily manage various schema elements in the Dataverse environment through standardized Web API interfaces.How to use Dataverse MCP Server?
Through simple HTTP requests or pre - built command - line tools, you can create, modify, and query metadata elements such as table structures, column definitions, and relationships in Dataverse.Use Cases
Suitable for development teams that need to automate the management of the Dataverse schema, especially in scenarios such as cross - environment deployment, continuous integration/continuous delivery (CI/CD) processes, and large - scale metadata management.Main Features
How to Use
Usage Examples
Frequently Asked Questions
Related Resources
Installation
{
"mcpServers": {
"dataverse": {
"command": "node",
"args": ["/path/to/mcp-dataverse/build/index.js"],
"disabled": false,
"alwaysAllow": [],
"disabledTools": [],
"timeout": 900
}
}
}
{
"mcpServers": {
"dataverse": {
"command": "node",
"args": ["/path/to/mcp-dataverse/build/index.js"],
"env": {
"DATAVERSE_URL": "https://yourorg.crm.dynamics.com",
"DATAVERSE_CLIENT_ID": "your-client-id",
"DATAVERSE_CLIENT_SECRET": "your-client-secret",
"DATAVERSE_TENANT_ID": "your-tenant-id"
},
"disabled": false,
"alwaysAllow": [],
"disabledTools": [],
"timeout": 900
}
}
}
{
"mcpServers": {
"dataverse": {
"command": "node",
"args": ["/path/to/mcp-dataverse/build/index.js"],
"env": {
"DATAVERSE_URL": "https://prod-org.crm.dynamics.com",
"DATAVERSE_CLIENT_ID": "prod-client-id",
"DATAVERSE_CLIENT_SECRET": "prod-client-secret"
},
"disabled": false,
"alwaysAllow": [],
"disabledTools": [],
"timeout": 900
}
}
}🚀 Dataverse MCP Server
The Dataverse MCP Server is a Model Context Protocol (MCP) server tailored for Microsoft Dataverse. It empowers users to perform schema operations via the Dataverse Web API, including creating and updating tables, columns, relationships, and option sets.
🚀 Quick Start
The Dataverse MCP Server provides a comprehensive set of tools for managing Dataverse schemas. Before you start, ensure you have access to a Microsoft Dataverse environment, an Azure AD app registration with appropriate permissions, and the necessary client credentials (Client ID, Client Secret, and Tenant ID).
✨ Features
Table Operations
- create_dataverse_table: Create new custom tables.
- get_dataverse_table: Retrieve table metadata.
- update_dataverse_table: Update table properties.
- delete_dataverse_table: Delete custom tables.
- list_dataverse_tables: List tables with filtering options.
Column Operations
- create_dataverse_column: Create columns of various types (see Supported Column Types below).
- get_dataverse_column: Retrieve column metadata.
- update_dataverse_column: Update column properties.
- delete_dataverse_column: Delete custom columns.
- list_dataverse_columns: List columns for a table.
Relationship Operations
- create_dataverse_relationship: Create One-to-Many or Many-to-Many relationships.
- get_dataverse_relationship: Retrieve relationship metadata.
- delete_dataverse_relationship: Delete custom relationships.
- list_dataverse_relationships: List relationships with filtering.
Option Set Operations
- create_dataverse_optionset: Create global option sets.
- get_dataverse_optionset: Retrieve option set metadata.
- update_dataverse_optionset: Update option sets (add/update/remove options).
- delete_dataverse_optionset: Delete custom option sets.
- list_dataverse_optionsets: List option sets.
- get_dataverse_optionset_options: Get options for a specific option set.
Solution & Publisher Operations
- create_dataverse_publisher: Create custom publishers with prefixes.
- get_dataverse_publisher: Retrieve publisher metadata.
- list_dataverse_publishers: List publishers with filtering.
- create_dataverse_solution: Create solutions linked to publishers.
- get_dataverse_solution: Retrieve solution metadata.
- list_dataverse_solutions: List solutions with publisher details.
- set_solution_context: Set active solution for schema operations.
- get_solution_context: View current solution context.
- clear_solution_context: Remove solution context.
Security Role Operations
- create_dataverse_role: Create new security roles.
- get_dataverse_role: Retrieve security role metadata.
- update_dataverse_role: Update security role properties.
- delete_dataverse_role: Delete custom security roles.
- list_dataverse_roles: List security roles with filtering options.
- add_privileges_to_role: Add privileges to a security role.
- remove_privilege_from_role: Remove privileges from a security role.
- replace_role_privileges: Replace all privileges for a security role.
- get_role_privileges: Retrieve all privileges for a security role.
- assign_role_to_user: Assign security roles to users.
- remove_role_from_user: Remove security roles from users.
- assign_role_to_team: Assign security roles to teams.
- remove_role_from_team: Remove security roles from teams.
Team Operations
- create_dataverse_team: Create new teams with various types and configurations.
- get_dataverse_team: Retrieve team metadata and details.
- update_dataverse_team: Update team properties and settings.
- delete_dataverse_team: Delete teams.
- list_dataverse_teams: List teams with filtering options.
- add_members_to_team: Add users as team members.
- remove_members_from_team: Remove users from teams.
- get_team_members: Retrieve all members of a team.
- convert_owner_team_to_access_team: Convert owner teams to access teams.
Business Unit Operations
- create_dataverse_businessunit: Create new business units with comprehensive address and contact information.
- get_dataverse_businessunit: Retrieve business unit metadata and details.
- update_dataverse_businessunit: Update business unit properties, addresses, and settings.
- delete_dataverse_businessunit: Delete business units.
- list_dataverse_businessunits: List business units with filtering and sorting options.
- get_businessunit_hierarchy: Retrieve the hierarchical structure of business units.
- set_businessunit_parent: Change the parent business unit in the hierarchy.
- get_businessunit_users: Get users associated with a business unit (with subsidiary option).
- get_businessunit_teams: Get teams associated with a business unit (with subsidiary option).
Schema Export Operations
- export_solution_schema: Export solution schema to JSON file including tables, columns, and global option sets. Supports filtering by customization prefix to export only solution-specific entities. Note: Relationship export is not yet implemented.
WebAPI Call Generator
- generate_webapi_call: Generate complete WebAPI calls for Dataverse operations including URLs, headers, and request bodies. Supports all major operations (retrieve, create, update, delete, associate, disassociate, actions, functions) with OData query options and provides output in multiple formats (HTTP, cURL, JavaScript fetch).
PowerPages WebAPI Generator
- generate_powerpages_webapi_call: Generate PowerPages-specific WebAPI calls using the
/_api/[logicalEntityName]format. Includes request verification token handling, authentication context, React component examples, and PowerPages-specific features for SPA development.
PowerPages Configuration Management
- manage_powerpages_webapi_config: Manage table permissions and WebAPI site settings for PowerPages Code Sites. Automates YAML configuration files in
.powerpages-sitedirectory including sitesetting.yml, webrole.yml, and table-permissions/*.yml files with comprehensive status checking and configuration management.
📦 Installation
Prerequisites
- Dataverse Environment: You need access to a Microsoft Dataverse environment.
- Azure App Registration: An Azure AD app registration with appropriate permissions.
- Client Credentials: Client ID, Client Secret, and Tenant ID for authentication.
Setup
1. Azure App Registration
- Go to the Azure Portal.
- Navigate to Azure Active Directory > App registrations.
- Click New registration.
- Provide a name (e.g., "Dataverse MCP Server").
- Select Accounts in this organizational directory only.
- Click Register.
2. Create Client Secret
- Go to Certificates & secrets.
- Click New client secret.
- Provide a description and expiration.
- Click Add.
- Copy the secret value immediately (you won't be able to see it again).
3. Create Application User in Dataverse
Critical Step: You must create an Application User in your Dataverse environment and assign appropriate permissions.
- Navigate to Dataverse Admin Center
- Go to Power Platform Admin Center.
- Select your environment.
- Go to Settings > Users + permissions > Application users.
- Create Application User
- Click + New app user.
- Click + Add an app.
- Search for and select your Azure app registration (by Client ID).
- Enter a Business unit (usually the root business unit).
- Click Create.
- Assign Security Roles
- Select the newly created application user.
- Click Manage roles.
- Assign appropriate security roles based on your needs:
- System Administrator: Full access (recommended for development/testing).
- System Customizer: Schema operations without data access.
- Custom Role: Create specific permissions for production use.
- Verify Application User Status
- Ensure the application user is Enabled.
- Verify it shows as Application type (not User).
- Note the Application ID matches your Azure app registration Client ID.
4. Get Required Information
You'll need:
- Tenant ID: Found in Azure AD > Overview.
- Client ID: Found in your app registration > Overview.
- Client Secret: The secret you just created.
- Dataverse URL: Your Dataverse environment URL (e.g.,
https://yourorg.crm.dynamics.com).
Installation Steps
- Install dependencies:
npm install
- Build the server:
npm run build
-
Copy the full path to the built
index.jsfile:- The server will be built to the
build/directory. - Copy the complete file path (e.g.,
/Users/yourname/path/to/mcp-dataverse/build/index.js). - You'll use this path in your MCP configuration file.
- The server will be built to the
-
Configure the MCP server in your MCP settings file using the copied path (see Configuration section below for details).
💻 Usage Examples
Creating a Custom Table
// Create a new custom table with automatic naming
// The system automatically generates:
// - Logical Name: xyz_project (using customization prefix from solution context)
// - Schema Name: xyz_Project (prefix lowercase, original case preserved, spaces removed)
// - Display Collection Name: Projects (auto-pluralized)
// - Primary Name Attribute: xyz_project_name
await use_mcp_tool("dataverse", "create_dataverse_table", {
displayName: "Project",
description: "Custom table for managing projects",
ownershipType: "UserOwned",
hasActivities: true,
hasNotes: true
});
// Example with minimal parameters (most common usage)
await use_mcp_tool("dataverse", "create_dataverse_table", {
displayName: "Customer Feedback"
});
// This creates:
// - Logical Name: xyz_customerfeedback
// - Schema Name: xyz_CustomerFeedback (prefix lowercase, original case preserved)
// - Display Collection Name: Customer Feedbacks
// - Primary Name Attribute: xyz_customerfeedback_name
Important: Before creating tables, ensure you have set a solution context using set_solution_context to provide the customization prefix. The system automatically uses the prefix from the active solution's publisher.
Adding Columns to a Table
// String column with email format and automatic naming
// The system automatically generates:
// - Logical Name: xyz_contactemail (prefix + lowercase, no spaces)
// - Schema Name: xyz_ContactEmail (prefix lowercase, original case preserved)
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
displayName: "Contact Email",
columnType: "String",
format: "Email",
maxLength: 100,
requiredLevel: "ApplicationRequired"
});
// Integer column with constraints (generates xyz_priorityscore)
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
displayName: "Priority Score",
columnType: "Integer",
minValue: 1,
maxValue: 10,
defaultValue: 5
});
// Boolean column with custom labels (generates xyz_isactive)
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
displayName: "Is Active",
columnType: "Boolean",
trueOptionLabel: "Active",
falseOptionLabel: "Inactive",
defaultValue: true
});
// DateTime column (date only) (generates xyz_startdate)
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
displayName: "Start Date",
columnType: "DateTime",
dateTimeFormat: "DateOnly",
requiredLevel: "ApplicationRequired"
});
// DateTime column (date and time) (generates xyz_lastmodified)
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
displayName: "Last Modified",
columnType: "DateTime",
dateTimeFormat: "DateAndTime"
});
// Picklist column with local options (generates xyz_status)
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
displayName: "Status",
columnType: "Picklist",
options: [
{ value: 1, label: "Planning" },
{ value: 2, label: "In Progress" },
{ value: 3, label: "On Hold" },
{ value: 4, label: "Completed" }
]
});
// Picklist column using global option set (generates xyz_projectcolor)
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
displayName: "Project Color",
columnType: "Picklist",
optionSetName: "xyz_colors"
});
// Lookup column (generates xyz_account)
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
displayName: "Account",
columnType: "Lookup",
targetEntity: "account"
});
// Memo column for long text (generates xyz_description)
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
displayName: "Description",
columnType: "Memo",
maxLength: 2000,
requiredLevel: "Recommended"
});
Creating Relationships
// Create a One-to-Many relationship
await use_mcp_tool("dataverse", "create_dataverse_relationship", {
relationshipType: "OneToMany",
schemaName: "new_account_project",
referencedEntity: "account",
referencingEntity: "new_project",
referencingAttributeLogicalName: "new_accountid",
referencingAttributeDisplayName: "Account",
cascadeDelete: "RemoveLink"
});
Managing Option Sets
// Create a global option set
await use_mcp_tool("dataverse", "create_dataverse_optionset", {
name: "new_priority",
displayName: "Priority Levels",
options: [
{ value: 1, label: "Low", color: "#00FF00" },
{ value: 2, label: "Medium", color: "#FFFF00" },
{ value: 3, label: "High", color: "#FF0000" }
]
});
Managing Security Roles
// Create a new security role
await use_mcp_tool("dataverse", "create_dataverse_role", {
name: "Project Manager",
description: "Role for project managers with specific permissions",
appliesTo: "Project management team members",
isAutoAssigned: false,
isInherited: "1",
summaryOfCoreTablePermissions: "Read/Write access to project-related tables"
});
// Get security role information
await use_mcp_tool("dataverse", "get_dataverse_role", {
roleId: "role-guid-here"
});
// List security roles
await use_mcp_tool("dataverse", "list_dataverse_roles", {
customOnly: true,
includeManaged: false,
top: 20
});
// Add privileges to a role
await use_mcp_tool("dataverse", "add_privileges_to_role", {
roleId: "role-guid-here",
privileges: [
{ privilegeId: "privilege-guid-1", depth: "Global" },
{ privilegeId: "privilege-guid-2", depth: "Local" }
]
});
// Assign role to a user
await use_mcp_tool("dataverse", "assign_role_to_user", {
roleId: "role-guid-here",
userId: "user-guid-here"
});
// Assign role to a team
await use_mcp_tool("dataverse", "assign_role_to_team", {
roleId: "role-guid-here",
teamId: "team-guid-here"
});
// Get role privileges
await use_mcp_tool("dataverse", "get_role_privileges", {
roleId: "role-guid-here"
});
Managing Teams
// Create a new team
await use_mcp_tool("dataverse", "create_dataverse_team", {
name: "Development Team",
description: "Team for software development activities",
administratorId: "admin-user-guid-here",
teamType: "0", // Owner team
membershipType: "0", // Members and guests
emailAddress: "devteam@company.com"
});
// Get team information
await use_mcp_tool("dataverse", "get_dataverse_team", {
teamId: "team-guid-here"
});
// List teams with filtering
await use_mcp_tool("dataverse", "list_dataverse_teams", {
teamType: "0", // Owner teams only
excludeDefault: true,
top: 20
});
// Add members to a team
await use_mcp_tool("dataverse", "add_members_to_team", {
teamId: "team-guid-here",
memberIds: ["user-guid-1", "user-guid-2", "user-guid-3"]
});
// Get team members
await use_mcp_tool("dataverse", "get_team_members", {
teamId: "team-guid-here"
});
// Remove members from a team
await use_mcp_tool("dataverse", "remove_members_from_team", {
teamId: "team-guid-here",
memberIds: ["user-guid-1", "user-guid-2"]
});
// Update team properties
await use_mcp_tool("dataverse", "update_dataverse_team", {
teamId: "team-guid-here",
name: "Updated Development Team",
description: "Updated description for the development team",
emailAddress: "newdevteam@company.com"
});
// Convert owner team to access team
await use_mcp_tool("dataverse", "convert_owner_team_to_access_team", {
teamId: "owner-team-guid-here"
});
Managing Business Units
// Create a new business unit with comprehensive information
await use_mcp_tool("dataverse", "create_dataverse_businessunit", {
name: "Sales Division",
description: "Business unit for sales operations",
divisionName: "Sales",
emailAddress: "sales@company.com",
costCenter: "SALES-001",
creditLimit: 100000,
parentBusinessUnitId: "parent-bu-guid-here",
// Address information
address1_name: "Sales Office",
address1_line1: "123 Business Street",
address1_city: "New York",
address1_stateorprovince: "NY",
address1_postalcode: "10001",
address1_country: "United States",
address1_telephone1: "+1-555-0123",
address1_fax: "+1-555-0124",
// Website and other details
webSiteUrl: "https://sales.company.com",
stockExchange: "NYSE",
tickerSymbol: "COMP"
});
// Get business unit information
await use_mcp_tool("dataverse", "get_dataverse_businessunit", {
businessUnitId: "business-unit-guid-here"
});
// List business units with filtering
await use_mcp_tool("dataverse", "list_dataverse_businessunits", {
filter: "isdisabled eq false",
orderby: "name asc",
top: 20
});
// Update business unit properties
await use_mcp_tool("dataverse", "update_dataverse_businessunit", {
businessUnitId: "business-unit-guid-here",
name: "Updated Sales Division",
description: "Updated description for sales operations",
emailAddress: "newsales@company.com",
creditLimit: 150000,
// Update address information
address1_line1: "456 New Business Avenue",
address1_telephone1: "+1-555-9999"
});
// Get business unit hierarchy
await use_mcp_tool("dataverse", "get_businessunit_hierarchy", {
businessUnitId: "business-unit-guid-here"
});
// Change business unit parent (reorganization)
await use_mcp_tool("dataverse", "set_businessunit_parent", {
businessUnitId: "child-bu-guid-here",
parentBusinessUnitId: "new-parent-bu-guid-here"
});
// Get users in a business unit
await use_mcp_tool("dataverse", "get_businessunit_users", {
businessUnitId: "business-unit-guid-here",
includeSubsidiaryUsers: false // Set to true to include users from child business units
});
// Get teams in a business unit
await use_mcp_tool("dataverse", "get_businessunit_teams", {
businessUnitId: "business-unit-guid-here",
includeSubsidiaryTeams: true // Include teams from subsidiary business units
});
// Delete a business unit (ensure no dependencies exist)
await use_mcp_tool("dataverse", "delete_dataverse_businessunit", {
businessUnitId: "business-unit-guid-here"
});
Exporting Solution Schema
// Export custom schema only (default settings)
// Exports tables, columns, and option sets to a JSON file
// Note: Relationship export is not yet implemented
await use_mcp_tool("dataverse", "export_solution_schema", {
outputPath: "my-solution-schema.json"
});
// Export with system entities included for comprehensive documentation
await use_mcp_tool("dataverse", "export_solution_schema", {
outputPath: "complete-schema.json",
includeSystemTables: true,
includeSystemColumns: true,
includeSystemOptionSets: true
});
// Export minified JSON for production use
await use_mcp_tool("dataverse", "export_solution_schema", {
outputPath: "schema-minified.json",
prettify: false
});
// Export to specific directory with custom settings
await use_mcp_tool("dataverse", "export_solution_schema", {
outputPath: "exports/solution-backup.json",
includeSystemTables: false,
includeSystemColumns: false,
includeSystemOptionSets: false,
prettify: true
});
// Export only tables matching solution customization prefix
await use_mcp_tool("dataverse", "export_solution_schema", {
outputPath: "prefix-only-schema.json",
includeSystemTables: false,
includeSystemColumns: false,
includeSystemOptionSets: false,
prefixOnly: true,
prettify: true
});
Schema Export Features:
- Schema Capture: Exports tables, columns, and global option sets (relationships not yet implemented).
- Flexible Filtering: Choose to include or exclude system entities.
- Solution Context Aware: Automatically includes solution metadata when context is set.
- Comprehensive Metadata: Captures all entity properties and column types.
- JSON Format: Human-readable or minified output options.
- Directory Creation: Automatically creates output directories if they don't exist.
Example Output Structure:
{
"metadata": {
"exportedAt": "2025-07-26T17:30:00.000Z",
"solutionUniqueName": "xyzsolution",
"solutionDisplayName": "XYZ Test Solution",
"publisherPrefix": "xyz",
"includeSystemTables": false,
"includeSystemColumns": false,
"includeSystemOptionSets": false
},
"tables": [
{
"logicalName": "xyz_project",
"displayName": "Project",
"schemaName": "xyz_Project",
"ownershipType": "UserOwned",
"isCustomEntity": true,
"columns": [
{
"logicalName": "xyz_name",
"displayName": "Name",
"attributeType": "String",
"maxLength": 100,
"isPrimaryName": true
}
]
}
],
"globalOptionSets": [
{
"name": "xyz_priority",
"displayName": "Priority Levels",
"isGlobal": true,
"options": [
{ "value": 1, "label": "Low" },
{ "value": 2, "label": "High" }
]
}
]
}
Note: Relationship export functionality is planned for a future release.
WebAPI Call Generator
// Generate a simple retrieve operation
await use_mcp_tool("dataverse", "generate_webapi_call", {
operation: "retrieve",
entitySetName: "accounts",
entityId: "12345678-1234-1234-1234-123456789012",
select: ["name", "emailaddress1", "telephone1"]
});
// Generate a retrieve multiple with filtering and sorting
await use_mcp_tool("dataverse", "generate_webapi_call", {
operation: "retrieveMultiple",
entitySetName: "contacts",
select: ["fullname", "emailaddress1"],
filter: "statecode eq 0 and contains(fullname,'John')",
orderby: "fullname asc",
top: 10,
count: true
});
// Generate a create operation with return preference
await use_mcp_tool("dataverse", "generate_webapi_call", {
operation: "create",
entitySetName: "accounts",
data: {
name: "Test Account",
emailaddress1: "test@example.com",
telephone1: "555-1234"
},
prefer: ["return=representation"],
includeAuthHeader: true
});
// Generate an update operation with conditional headers
await use_mcp_tool("dataverse", "generate_webapi_call", {
operation: "update",
entitySetName: "accounts",
entityId: "12345678-1234-1234-1234-123456789012",
data: {
name: "Updated Account Name",
telephone1: "555-5678"
},
ifMatch: "*"
});
// Generate an associate operation for relationships
await use_mcp_tool("dataverse", "generate_webapi_call", {
operation: "associate",
entitySetName: "accounts",
entityId: "12345678-1234-1234-1234-123456789012",
relationshipName: "account_primary_contact",
relatedEntitySetName: "contacts",
relatedEntityId: "87654321-4321-4321-4321-210987654321"
});
// Generate a bound action call
await use_mcp_tool("dataverse", "generate_webapi_call", {
operation: "callAction",
actionOrFunctionName: "WinOpportunity",
entitySetName: "opportunities",
entityId: "11111111-1111-1111-1111-111111111111",
parameters: {
Status: 3,
Subject: "Won Opportunity"
}
});
// Generate an unbound function call
await use_mcp_tool("dataverse", "generate_webapi_call", {
operation: "callFunction",
actionOrFunctionName: "WhoAmI",
includeAuthHeader: true
});
// Generate a function call with parameters
await use_mcp_tool("dataverse", "generate_webapi_call", {
operation: "callFunction",
actionOrFunctionName: "GetTimeZoneCodeByLocalizedName",
parameters: {
LocalizedStandardName: "Pacific Standard Time",
LocaleId: 1033
}
});
Output Features:
- Complete HTTP Request: Method, URL, headers, and body.
- cURL Command: Ready-to-execute command-line example.
- JavaScript Fetch: Copy-paste JavaScript code.
- Solution Context: Automatically includes current solution headers.
- Authentication Placeholder: Optional Bearer token placeholder.
- OData Query Building: Proper encoding of complex filter expressions.
Example Output:
HTTP Method: GET
URL: https://yourorg.crm.dynamics.com/api/data/v9.2/accounts(12345678-1234-1234-1234-123456789012)?$select=name,emailaddress1,telephone1
Headers:
Content-Type: application/json
Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0
MSCRM.SolutionUniqueName: xyzsolution
--- Additional Information ---
Operation Type: retrieve
Entity Set: accounts
Entity ID: 12345678-1234-1234-1234-123456789012
Curl Command:
curl -X GET \
"https://yourorg.crm.dynamics.com/api/data/v9.2/accounts(12345678-1234-1234-1234-123456789012)?$select=name,emailaddress1,telephone1" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "OData-MaxVersion: 4.0" \
-H "OData-Version: 4.0" \
-H "MSCRM.SolutionUniqueName: xyzsolution"
JavaScript Fetch Example:
fetch('https://yourorg.crm.dynamics.com/api/data/v9.2/accounts(12345678-1234-1234-1234-123456789012)?$select=name,emailaddress1,telephone1', {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"MSCRM.SolutionUniqueName": "xyzsolution"
}
})
.then(response => response.json())
.then(data => console.log(data));
Supported Operations:
- retrieve: Get a single record by ID.
- retrieveMultiple: Query multiple records with OData.
- create: Create new records.
- update: Update existing records (PATCH).
- delete: Delete records.
- associate: Create relationships between records.
- disassociate: Remove relationships between records.
- callAction: Execute Dataverse actions (bound/unbound).
- callFunction: Execute Dataverse functions (bound/unbound).
Advanced Features:
- OData Query Options: $select, $filter, $orderby, $top, $skip, $expand, $count.
- Prefer Headers: return=representation, odata.include-annotations=*.
- Conditional Updates: If-Match, If-None-Match headers.
- Impersonation: MSCRMCallerID header support.
- Solution Context: Automatic MSCRM.SolutionUniqueName header inclusion.
PowerPages WebAPI Generator
// Generate a PowerPages retrieve multiple operation
await use_mcp_tool("dataverse", "generate_powerpages_webapi_call", {
operation: "retrieveMultiple",
logicalEntityName: "cr7ae_creditcardses",
select: ["cr7ae_name", "cr7ae_type", "cr7ae_features"],
filter: "cr7ae_type eq 'Premium'",
orderby: "cr7ae_name asc",
top: 10,
baseUrl: "https://contoso.powerappsportals.com",
includeAuthContext: true
});
// Generate a PowerPages create operation with request verification token
await use_mcp_tool("dataverse", "generate_powerpages_webapi_call", {
operation: "create",
logicalEntityName: "cr7ae_creditcardses",
data: {
cr7ae_name: "New Premium Card",
cr7ae_type: "Premium",
cr7ae_features: "Cashback, Travel Insurance"
},
baseUrl: "https://contoso.powerappsportals.com",
requestVerificationToken: true
});
// Generate a PowerPages retrieve single record
await use_mcp_tool("dataverse", "generate_powerpages_webapi_call", {
operation: "retrieve",
logicalEntityName: "contacts",
entityId: "12345678-1234-1234-1234-123456789012",
select: ["fullname", "emailaddress1", "telephone1"],
baseUrl: "https://yoursite.powerappsportals.com"
});
// Generate with custom headers for advanced scenarios
await use_mcp_tool("dataverse", "generate_powerpages_webapi_call", {
operation: "retrieveMultiple",
logicalEntityName: "contacts",
select: ["fullname", "emailaddress1"],
filter: "contains(fullname,'John')",
customHeaders: {
"X-Custom-Header": "PowerPages-API",
"X-Client-Version": "1.0"
}
});
Output Features:
- PowerPages URL Format: Correct
/_api/[logicalEntityName]sendpoint construction (automatic 's' suffix). - Request Verification Token: Automatic token handling for POST/PATCH/DELETE operations.
- JavaScript Examples: Ready-to-use fetch code with error handling.
- React Components: Complete React hook examples for data fetching.
- Authentication Context: PowerPages user context and token management.
- OData Query Support: Full OData query parameter support with proper encoding.
Example Output:
// PowerPages WebAPI Call
const fetchData = async () => {
// Get the request verification token
const token = document.querySelector('input[name="__RequestVerificationToken"]')?.value;
try {
const response = await fetch('/_api/cr7ae_creditcardses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'__RequestVerificationToken': token
},
body: JSON.stringify({
"cr7ae_name": "New Premium Card",
"cr7ae_type": "Premium",
"cr7ae_features": "Cashback, Travel Insurance"
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const createdRecord = await response.json();
console.log('Created record:', createdRecord);
return createdRecord;
} catch (error) {
console.error('Error:', error);
throw error;
}
};
React Component Example:
// React Hook Example
import React, { useState, useEffect } from 'react';
const CreditCardsList = () => {
const [records, setRecords] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchRecords = async () => {
try {
const response = await fetch('/_api/cr7ae_creditcardses?$select=cr7ae_name,cr7ae_type');
const data = await response.json();
setRecords(data.value);
} catch (error) {
console.error('Error fetching records:', error);
} finally {
setLoading(false);
}
};
fetchRecords();
}, []);
if (loading) return <div>Loading...</div>;
return (
<div>
<h2>Credit Cards</h2>
{records.map((record, index) => (
<div key={record.cr7ae_creditcardsesid || index}>
<h3>{record.cr7ae_name}</h3>
<p>Type: {record.cr7ae_type}</p>
</div>
))}
</div>
);
};
Authentication Context Integration:
// Access user information in PowerPages
const user = window["Microsoft"]?.Dynamic365?.Portal?.User;
const userName = user?.userName || "";
const firstName = user?.firstName || "";
const lastName = user?.lastName || "";
const isAuthenticated = userName !== "";
// Get authentication token (if needed)
const getToken = async () => {
try {
const token = await window.shell.getTokenDeferred();
return token;
} catch (error) {
console.error('Error fetching token:', error);
return null;
}
};
PowerPages-Specific Features:
- Request Verification Token: Automatic
__RequestVerificationTokenheader handling for secure operations. - Authentication Integration: Built-in PowerPages user context access.
- React-Ready: Complete React component examples with hooks and state management.
- Error Handling: Comprehensive error handling patterns for PowerPages environments.
- Security Compliance: Respects PowerPages table permissions and web role security.
- SPA Optimization: Designed for single-page application development patterns.
Supported Operations:
- retrieve: Get a single record by ID.
- retrieveMultiple: Query multiple records with OData filtering.
- create: Create new records with request verification token.
- update: Update existing records (PATCH) with token handling.
- delete: Delete records with proper authentication.
This tool is essential for PowerPages developers building modern SPAs that need to interact with Dataverse data while maintaining PowerPages security and authentication patterns.
PowerPages Configuration Management
Key Features
- Automated YAML Management: Creates and updates sitesetting.yml, webrole.yml, and table permission files.
- WebAPI Configuration: Enables WebAPI access with proper site settings.
- Table Permissions: Manages granular permissions for specific tables and web roles.
- Status Checking: Provides comprehensive status of current configurations.
- PowerPages Code Site Integration: Works seamlessly with the
.powerpages-sitedirectory structure.
Usage Examples
Check Configuration Status
{
"operation": "status"
}
Sample Output:
PowerPages WebAPI Configuration Status:
WebAPI Configuration:
✅ WebAPI is enabled (Webapi/cr7ae_creditcardses/Enabled = true)
✅ WebAPI fields are configured (Webapi/cr7ae_creditcardses/Fields = cr7ae_name,cr7ae_type,cr7ae_limit)
Web Roles:
✅ Authenticated Users role exists
✅ Anonymous Users role exists
Table Permissions:
✅ cr7ae_creditcardses permissions configured for Authenticated Users
- Read: ✅, Create: ✅, Write: ✅, Delete: ❌
- Scope: Global
Enable WebAPI for a Table
{
"operation": "configure-webapi",
"tableName": "cr7ae_creditcardses",
"fields": ["cr7ae_name", "cr7ae_type", "cr7ae_limit", "cr7ae_isactive"],
"enabled": true
}
Result:
- Updates
.powerpages-site/sitesetting.ymlwith WebAPI settings. - Enables WebAPI access for the specified table.
- Configures allowed fields for WebAPI operations.
Create Table Permissions
{
"operation": "create-table-permission",
"tableName": "cr7ae_creditcardses",
"webRoleName": "Authenticated Users",
"permissions": {
"read": true,
"create": true,
"write": true,
"delete": false
},
"scope": "Global"
}
Result:
- Creates
.powerpages-site/table-permissions/cr7ae_creditcardses_authenticated_users.yml. - Configures specific CRUD permissions for the web role.
- Sets appropriate scope (Global, Contact, Account, Self, Parent, etc.).
List Current Configurations
{
"operation": "list-configurations"
}
Sample Output:
Current PowerPages Configurations:
Site Settings (3 total):
- Webapi/cr7ae_creditcardses/Enabled = true
- Webapi/cr7ae_creditcardses/Fields = cr7ae_name,cr7ae_type,cr7ae_limit
- Authentication/Registration/Enabled = true
Web Roles (2 total):
- Authenticated Users (ID: 12345678-1234-1234-1234-123456789012)
- Anonymous Users (ID: 87654321-4321-4321-4321-210987654321)
Table Permissions (1 total):
- cr7ae_creditcardses_authenticated_users.yml
Table: cr7ae_creditcardses, Role: Authenticated Users
Permissions: Read ✅, Create ✅, Write ✅, Delete ❌
Scope: Global
Operations
status
Provides a comprehensive overview of the current PowerPages WebAPI configuration including:
- WebAPI enablement status for tables.
- Configured fields and permissions.
- Web role definitions.
- Table permission summaries.
configure-webapi
Enables or configures WebAPI access for specific tables:
- tableName (required): Logical name of the table.
- fields (optional): Array of field names to allow in WebAPI calls.
- enabled (optional): Boolean to enable/disable WebAPI access.
create-table-permission
Creates granular table permissions for web roles:
- tableName (required): Logical name of the table.
- webRoleName (required): Name of the web role.
- permissions (required): Object with read, create, write, delete boolean values.
- scope (optional): Permission scope (Global, Contact, Account, Self, Parent, etc.).
list-configurations
Lists all current configurations including:
- Site settings with their values.
- Web roles with IDs.
- Table permissions with detailed permission breakdown.
PowerPages Code Site Integration
This tool is designed to work with PowerPages Code Sites that follow the standard directory structure:
your-powerpages-project/
├── .powerpages-site/
│ ├── sitesetting.yml # WebAPI and other site settings
│ ├── webrole.yml # Web role definitions
│ └── table-permissions/ # Individual permission files
│ ├── cr7ae_creditcardses_authenticated_users.yml
│ └── contact_anonymous_users.yml
├── src/ # Your React components
└── package.json
Example Workflow
-
Check Current Status:
{"operation": "status"} -
Enable WebAPI for Your Custom Table:
{ "operation": "configure-webapi", "tableName": "cr7ae_creditcardses", "fields": ["cr7ae_name", "cr7ae_type", "cr7ae_limit"], "enabled": true } -
Create Table Permissions:
{ "operation": "create-table-permission", "tableName": "cr7ae_creditcardses", "webRoleName": "Authenticated Users", "permissions": { "read": true, "create": true, "write": true, "delete": false }, "scope": "Global" } -
Verify Configuration:
{"operation": "list-configurations"} -
Use with PowerPages WebAPI Generator:
{ "operation": "retrieveMultiple", "logicalEntityName": "cr7ae_creditcardses", "select": ["cr7ae_name", "cr7ae_type", "cr7ae_limit"] }
This workflow ensures your PowerPages Code Site is properly configured to handle WebAPI calls for your custom tables with appropriate security permissions.
🔧 Technical Details
Solution-Based Architecture
The MCP server implements enterprise-grade solution management following Microsoft Dataverse best practices.
Key Benefits
- Professional Schema Naming: Uses publisher-based customization prefixes.
- Solution Association: All schema changes are automatically associated with the active solution.
- ALM Support: Enables proper solution packaging and deployment across environments.
- Persistent Context: Solution context survives server restarts via
.mcp-dataversefile. - Enterprise Governance: Supports multiple publishers and solutions with proper isolation.
Solution Workflow
- Create Publisher: Define your organization's customization prefix.
- Create Solution: Link solution to publisher for schema organization.
- Set Context: Activate solution for subsequent operations.
- Create Schema: All tables, columns, and option sets use the publisher's prefix automatically.
- Deploy: Export solution for deployment to other environments.
Example: XYZ Organization Setup
// 1. Create publisher with "xyz" prefix
await use_mcp_tool("dataverse", "create_dataverse_publisher", {
friendlyName: "XYZ Test Publisher",
uniqueName: "xyzpublisher",
customizationPrefix: "xyz",
customizationOptionValuePrefix: 20000,
description: "Publisher for XYZ organization"
});
// 2. Create solution linked to publisher
await use_mcp_tool("dataverse", "create_dataverse_solution", {
friendlyName: "XYZ Test Solution",
uniqueName: "xyzsolution",
publisherUniqueName: "xyzpublisher",
description: "Main solution for XYZ customizations"
});
// 3. Set solution context (persisted across server restarts)
await use_mcp_tool("dataverse", "set_solution_context", {
solutionUniqueName: "xyzsolution"
});
// 4. Create schema objects - they automatically use "xyz" prefix
await use_mcp_tool("dataverse", "create_dataverse_table", {
logicalName: "xyz_project", // Uses xyz prefix automatically
displayName: "Project",
displayCollectionName: "XYZ Projects"
});
await use_mcp_tool("dataverse", "create_dataverse_column", {
entityLogicalName: "xyz_project",
logicalName: "xyz_description", // Uses xyz prefix automatically
displayName: "Description",
columnType: "Memo"
});
Persistent Solution Context
The server automatically persists solution context to a .mcp-dataverse file in the project root:
{
"solutionUniqueName": "xyzsolution",
"solutionDisplayName": "XYZ Test Solution",
"publisherUniqueName": "xyzpublisher",
"publisherDisplayName": "XYZ Test Publisher",
"customizationPrefix": "xyz",
"lastUpdated": "2025-07-26T08:27:56.966Z"
}
Benefits of Persistence:
- No Context Loss: Solution context survives server restarts.
- Instant Productivity: Developers can immediately continue work.
- Consistent Prefixes: No need to remember and re-set solution context.
- Team Isolation: Each developer can have their own solution context (file is git-ignored).
Supported Column Types
The MCP server supports all major Dataverse column types with comprehensive configuration options. The following table shows implementation status and testing verification:
| Column Type | Status | Tested | Description | Key Parameters |
|---|---|---|---|---|
| String | ✅ Implemented | ✅ Verified | Text fields with format options | maxLength, format (Email, Text, TextArea, Url, Phone) |
| Integer | ✅ Implemented | ✅ Verified | Whole numbers with constraints | minValue, maxValue, defaultValue |
| Decimal | ✅ Implemented | ⚠️ Not Tested | Decimal numbers with precision | precision, minValue, maxValue, defaultValue |
| Money | ✅ Implemented | ⚠️ Not Tested | Currency values | precision, minValue, maxValue |
| Boolean | ✅ Implemented | ✅ Verified | True/false with custom labels | trueOptionLabel, falseOptionLabel, defaultValue |
| DateTime | ✅ Implemented | ✅ Verified | Date and time fields | dateTimeFormat (DateOnly, DateAndTime) |
| Picklist | ✅ Implemented | ✅ Verified | Choice fields (local & global) | options (for local), optionSetName (for global) |
| Lookup | ✅ Implemented | ✅ Verified | References to other tables | targetEntity |
| Memo | ✅ Implemented | ⚠️ Not Tested | Long text fields | maxLength |
| Double | ✅ Implemented | ⚠️ Not Tested | Floating-point numbers | precision, minValue, maxValue |
| BigInt | ✅ Implemented | ⚠️ Not Tested | Large integer values | None |
Column Type Details
String Columns ✅ Tested
- Formats: Email, Text, TextArea, Url, Phone.
- Max Length: Configurable (default: 100).
- Default Values: Supported.
- Example: Employee name, email address, phone number.
Integer Columns ✅ Tested
- Constraints: Min/max value validation.
- Default Values: Supported.
- Example: Age, quantity, score with range 0-100.
Boolean Columns ✅ Tested
- Custom Labels: Configurable true/false option labels.
- Default Values: Supported.
- Example: "Active/Inactive", "Yes/No", "Enabled/Disabled".
DateTime Columns ✅ Tested
- DateOnly: Date without time component (e.g., hire date, birthday).
- DateAndTime: Full timestamp with timezone handling (e.g., last login, created date).
- Behavior: Uses UserLocal timezone behavior.
Picklist Columns ✅ Tested
- Local Option Sets: Create inline options with the column.
- Global Option Sets: Reference existing global option sets by name.
- Color Support: Options can have associated colors.
- Example: Status (Active, Inactive), Priority (High, Medium, Low).
Lookup Columns ✅ Tested
- Target Entity: Specify which table to reference.
- Relationships: Automatically creates underlying relationship.
- Example: Customer lookup, Account reference.
Tested Column Scenarios
The following specific scenarios have been successfully tested and verified:
- String Column Creation ✅
- Basic text field with default settings.
- Email format validation.
- Custom max length constraints.
- Integer Column Creation ✅
- Numeric field with min/max constraints (0-100 range).
- Default value assignment.
- Boolean Column Creation ✅
- Custom true/false labels ("Active"/"Inactive").
- Default value configuration.
- DateTime Column Creation ✅
- DateOnly format for hire dates.
- DateAndTime format for login timestamps.
- Picklist Column Creation ✅
- Local option set with custom options.
- Global option set reference using existing "Colors" option set.
- Lookup Column Creation ✅
- Cross-table reference (MCP Test 2 → MCP Test).
- Automatic relationship creation.
Column Operations Status
| Operation | Status | Description |
|---|---|---|
| Create | ✅ Fully Tested | All column types with type-specific parameters |
| Read | ✅ Implemented | Retrieve column metadata and configuration |
| Update | ✅ Implemented | Modify display name, description, required level |
| Delete | ✅ Tested | Remove custom columns from tables |
| List | ✅ Implemented | List all columns for a table with filtering |
Authentication
The server uses Client Credentials flow (Server-to-Server authentication) with Azure AD. This provides:
- Secure authentication without user interaction.
- Application-level permissions.
- Suitable for automated scenarios.
- Token refresh handling.
Error Handling
The server includes comprehensive error handling:
- Authentication errors: Invalid credentials or expired tokens.
- API errors: Dataverse-specific error messages with codes.
- Validation errors: Parameter validation and type checking.
- Network errors: Connection and timeout handling.
Security Considerations
- Store secrets securely: Never commit client secrets to version control.
- Use environment variables: Configure secrets through environment variables.
- Principle of least privilege: Grant only necessary permissions.
- Monitor usage: Track API calls and authentication attempts.
- Rotate secrets regularly: Update client secrets periodically.
Troubleshooting
Common Issues
- Authentication Failed
- Verify client ID, secret, and tenant ID.
- Check that the app registration is properly configured.
- Permission Denied
- Verify Application User Exists: Check that an application user has been created in Dataverse for your app registration.
- Check Security Roles: Ensure the application user has appropriate security roles:
- System Administrator: Required for full schema operations.
- System Customizer: Minimum for table/column operations.
- Environment Maker: May be needed for solution operations.
- Verify User Status: Ensure the application user is enabled and not disabled.
- Check Business Unit: Verify the application user is assigned to the correct business unit.
- Validate Client ID: Confirm the Application ID in Dataverse matches your Azure app registration Client ID.
- Entity Not Found
- Verify entity logical names are correct.
- Check if entities exist in the target environment.
- Invalid Column Type
- Review supported column types in the documentation.
- Verify required parameters for specific column types.
Debug Mode
Set environment variable DEBUG=true for verbose logging:
DEBUG=true node build/index.js
API Reference
For detailed parameter information for each tool, refer to the tool definitions in the source code:
- - Table operations.
- - Column operations.
- - Relationship operations.
- - Option set operations.
- - Solution and publisher operations.
- - Security role operations.
- - Team operations.
- - Business unit operations.
- - Schema export operations.
- - WebAPI call generator operations.
- - PowerPages WebAPI call generator operations.
- - PowerPages configuration management operations.
Solution Management Best Practices
Publisher Configuration
When creating publishers, follow these guidelines:
- Unique Prefixes: Use 2-8 character prefixes that identify your organization.
- Option Value Ranges: Use non-overlapping ranges (e.g., 10000-19999 for one publisher, 20000-29999 for another).
- Descriptive Names: Use clear, professional names for publishers and solutions.
Solution Context Management
// Check current context
await use_mcp_tool("dataverse", "get_solution_context", {});
// Switch to different solution
await use_mcp_tool("dataverse", "set_solution_context", {
solutionUniqueName: "anothersolution"
});
// Clear context (removes persistence file)
await use_mcp_tool("dataverse", "clear_solution_context", {});
Environment Promotion
- Development: Create and test schema changes in dev environment with solution context.
- Export: Use Power Platform CLI or admin center to export solution.
- Import: Deploy solution to test/production environments.
- Validation: Verify all customizations use proper prefixes.
Git Integration
The .mcp-dataverse file is automatically excluded from version control:
# MCP Dataverse context file
.mcp-dataverse
This allows each developer to maintain their own solution context while preventing accidental sharing of environment-specific settings.
Contributing
- Fork the repository.
- Create a feature branch.
- Make your changes.
- Add tests if applicable.
- Submit a pull request.
Changelog
For a detailed history of changes, new features, and bug fixes, see the CHANGELOG.md file.
Recent Updates
- v0.1.2: Added comprehensive Security Role Management system with 13 new tools.
- v0.1.1: Introduced Solution-Based Architecture with persistent context.
- v0.1.0: Initial release with core table, column, relationship, and option set operations.
The changelog follows Keep a Changelog format and includes:
- Added: New features and capabilities.
- Changed: Modifications to existing functionality.
- Fixed: Bug fixes and corrections.
- Security: Security-related updates.
📄 License
MIT License - see LICENSE file for details.
Support
For issues and questions:
- Check the troubleshooting section.
- Review Dataverse Web API documentation.
- Create an issue in the repository.
Alternatives








