Version: 0.7.5 | API Version: Dataverse Web API v9.2 | Transport: stdio · HTTP/SSE
79 tools across 27 categories for full Dataverse lifecycle: schema, CRUD, FetchXML, solutions, plugins, audit, files, users, teams, RBAC, attribute management, environment variables, workflows, schema write, record access, and more.
- Quick Start
- Architecture Overview
- Tool Reference (79 tools)
- 1. Auth (1)
- 2. Metadata (9)
- 3. Query (3)
- 4. CRUD (6)
- 5. Relations (4)
- 6. Actions & Functions (6)
- 7. Batch (1)
- 8. Change Tracking (1)
- 9. Solutions (2)
- 10. Impersonation (1)
- 11. Customization (4)
- 12. Environment (4)
- 13. Trace (2)
- 14. Search (1)
- 15. Audit (1)
- 16. Quality (1)
- 17. Annotations (2)
- 18. Users (2)
- 19. Views (1)
- 20. Files (2)
- 21. Org (2)
- 22. RBAC (7)
- 23. Workflows (4)
- 24. Assistance (2)
- 25. Attributes (4)
- 26. Schema (write) (2)
- 27. Record Access (4)
- Error Handling & Retry Behavior
- Security
- Limitations & Known Constraints
| Requirement | Details |
|---|---|
| Node.js | v20+ |
| Dataverse Environment | Active URL (https://<org>.crm<N>.dynamics.com) |
| Authentication | Device code flow (interactive) via MSAL |
npm install && npm run buildCreate config.json (see config.example.json):
{
"environmentUrl": "https://yourorg.crm.dynamics.com",
"requestTimeoutMs": 30000,
"maxRetries": 3
}| Field | Type | Description |
|---|---|---|
environmentUrl |
string |
Dataverse environment URL (required, must be HTTPS) |
requestTimeoutMs |
number |
HTTP timeout ms (default: 30000) |
maxRetries |
number |
Max retry attempts 0–10 (default: 3) |
Env vars override config: DATAVERSE_ENV_URL, REQUEST_TIMEOUT_MS, MAX_RETRIES.
The server uses Microsoft’s device code flow (MSAL Public Client). On first launch, a sign-in code is displayed in the VS Code Output panel. Open https://microsoft.com/devicelogin, paste the code, and sign in with your Power Platform work account. Tokens are cached in ~/.mcp-dataverse/ (encrypted) and renewed automatically.
npm run start # production
npm run dev # watch modeServer communicates over stdio (MCP SDK StdioServerTransport). Connect from any MCP host (VS Code Copilot, Claude Desktop, etc.) by configuring it to spawn the process.
graph LR
MCP["MCP Dataverse Server<br/><i>79 tools · 27 categories</i>"]
MCP --> AUTH["🔑 Auth (1)"]
MCP --> META["📋 Metadata (9)"]
MCP --> QUERY["🔍 Query (3)"]
MCP --> CRUD["✏️ CRUD (6)"]
MCP --> REL["🔗 Relations (4)"]
MCP --> ACT["⚡ Actions & Functions (6)"]
MCP --> BATCH["📦 Batch (1)"]
MCP --> TRACK["🔄 Change Tracking (1)"]
MCP --> SOL["🧩 Solutions (2)"]
MCP --> IMP["👤 Impersonation (1)"]
MCP --> CUST["🔧 Customization (4)"]
MCP --> ENV["⚙️ Environment (4)"]
MCP --> TRACE["🔎 Trace (2)"]
MCP --> SRCH["🔍 Search (1)"]
MCP --> AUDIT["📜 Audit (1)"]
MCP --> QUAL["✅ Quality (1)"]
MCP --> NOTE["📝 Annotations (2)"]
MCP --> USR["👥 Users (2)"]
MCP --> RBAC["🛡️ RBAC (7)"]
MCP --> VIEWS["👁️ Views (1)"]
MCP --> FILES["📁 Files (2)"]
MCP --> ORG["🏢 Org (2)"]
MCP --> WF["⚙️ Workflows (4)"]
MCP --> ASSIST["🤖 Assistance (2)"]
MCP --> ATTR["🏗️ Attributes (4)"]
MCP --> SCHEMA["📐 Schema write (2)"]
MCP --> ACCESS["🔐 Record Access (4)"]
All tool handlers validate inputs with Zod before calling the DataverseAdvancedClient. Auth tokens are cached and refreshed proactively; transient errors (429, 503, 504) are retried with exponential backoff.
Returns the current authenticated user context (userId, businessUnitId, organizationId, organizationName, environmentUrl). No parameters required.
"Who am I in Dataverse?"
Lists all Dataverse tables. Defaults to custom tables only; set includeSystemTables=true for all ~1700+ system tables.
| Parameter | Type | Req | Notes |
|---|---|---|---|
includeSystemTables |
boolean |
— | Default false |
"List all custom tables in my environment"
Returns full schema for a table: column logical names, display names, data types, required levels, lookup targets. Set includeAttributes=false for table-level info only.
| Parameter | Type | Req | Notes |
|---|---|---|---|
logicalName |
string |
✓ | e.g. "account" |
includeAttributes |
boolean |
— | Default true |
"Show me the schema for the contact table"
Returns 1:N, N:1, and N:N relationships for a table. Use to find the correct relationshipName for associate/disassociate.
| Parameter | Type | Req | Notes |
|---|---|---|---|
logicalName |
string |
✓ | Table logical name |
relationshipType |
"OneToMany"|"ManyToOne"|"ManyToMany"|"All" |
— | Default "All" |
"What relationships does the account table have?"
Lists all global (shared) option sets in the environment. No parameters required.
"List all global option sets in my environment"
Returns all labels and integer values for a named global option set.
| Parameter | Type | Req | Notes |
|---|---|---|---|
name |
string |
✓ | Global option set name |
"Show me the values for the budgetstatus option set"
Returns alternate key definitions for a table: key attributes, index status (Active/InProgress/Failed), and customizability.
| Parameter | Type | Req | Notes |
|---|---|---|---|
tableName |
string |
✓ | Table logical name |
"What alternate keys are defined on the account table?"
Returns all labels and integer values for a table-specific Picklist, Status, or State attribute. Use instead of dataverse_get_option_set for column-local choices.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entityLogicalName |
string |
✓ | e.g. "account" |
attributeLogicalName |
string |
✓ | e.g. "statuscode", "industrycode" |
"What are the valid statuscode values for opportunity?"
Resolves entity names bidirectionally: input a logicalName (e.g. account) or entitySetName (e.g. accounts) and get both representations plus metadata. Essential for avoiding 404/0x80060888 errors caused by using logicalName in OData URLs (which require entitySetName).
| Parameter | Type | Req | Notes |
|---|---|---|---|
name |
string |
✓ | Entity name to resolve — logicalName or entitySetName |
"What is the entitySetName for the 'account' entity?"
Updates configuration flags on an existing Dataverse entity definition — enables or disables Notes (HasNotes), Change Tracking, and Audit. Requires System Customizer or System Administrator privileges.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entityLogicalName |
string |
✓ | Logical name of the entity to update (e.g. account, new_mytable) |
confirm |
boolean |
✓ | Must be true — confirms intentional schema modification |
hasNotes |
boolean |
– | Enable or disable Notes/Attachments for this entity |
changeTrackingEnabled |
boolean |
– | Enable or disable change tracking (required for delta sync) |
isAuditEnabled |
boolean |
– | Enable or disable auditing on this entity |
autoPublish |
boolean |
– | Publish automatically after update (default: false) |
"Enable notes/attachments on the 'new_myentity' table."
OData query with $filter, $select, $orderby, $top, $expand, $count, and $apply (aggregations).
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | e.g. "accounts" |
select |
string[] |
— | Recommended — minimizes payload |
filter |
string |
— | OData $filter expression |
orderby |
string |
— | OData $orderby expression |
top |
number |
— | Default 50, max 5000 |
expand |
string |
— | OData $expand |
count |
boolean |
— | Include @odata.count |
"Show me the first 10 active accounts sorted by name"
Executes a FetchXML query — use for aggregations, complex joins, many-to-many traversal, and filters not expressible in OData.
| Parameter | Type | Req | Notes |
|---|---|---|---|
fetchXml |
string |
✓ | Complete FetchXML string |
entitySetName |
string |
— | Auto-extracted from <entity name="..."> if omitted |
"Run a FetchXML query to count opportunities grouped by status"
Retrieves ALL matching records by auto-following @odata.nextLink pages. Use when > 5000 records are needed.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
select |
string[] |
— | Columns to return |
filter |
string |
— | OData $filter |
orderby |
string |
— | OData $orderby |
expand |
string |
— | OData $expand |
maxTotal |
number |
— | Default 5000, max 50000 |
"Get all contacts with email addresses, up to 20000 records"
{ "records": [...], "totalRetrieved": 12345, "pageCount": 3 }Retrieves a single record by GUID. Returns the record plus @odata.etag.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
id |
string (UUID) |
✓ | Record GUID |
select |
string[] |
— | Columns to return |
"Get the account record with ID a1b2c3d4-..."
Creates a new record and returns its GUID. Use @odata.bind for lookup fields.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
data |
object |
✓ | Field key-value pairs using logical names |
"Create a new account called 'Fabrikam Inc.'"
PATCH-updates an existing record (only supplied fields change). Sends If-Match: *.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
id |
string (UUID) |
✓ | Record GUID |
data |
object |
✓ | Fields to update |
"Update account a1b2c3d4 — set revenue to 5000000"
Permanently deletes a record. Irreversible. confirm must be true.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
id |
string (UUID) |
✓ | Record GUID |
confirm |
boolean |
✓ | Must be true to proceed |
"Delete account record a1b2c3d4-..."
Create-or-update via an alternate key (no GUID needed). Returns "created" or "updated".
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
alternateKey |
string |
✓ | Alternate key attribute name |
alternateKeyValue |
string |
✓ | Value for the alternate key |
data |
object |
✓ | Record data |
mode |
"upsert"|"createOnly"|"updateOnly" |
— | Default "upsert" |
"Upsert account with external ID 'EXT-001', set name to 'Contoso'"
{
"operation": "created",
"id": "d4e5f6a7-...",
"message": "Record created successfully"
}Assigns a Dataverse record to a different user or team owner. Sets the ownerid lookup field using OData bind syntax.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
id |
string (UUID) |
✓ | Record GUID to reassign |
ownerType |
"systemuser"|"team" |
✓ | Target owner type |
ownerId |
string (UUID) |
✓ | GUID of user or team |
"Reassign account a1b2c3d4 to user u1v2w3x4"
Creates an N:N or 1:N association between two records via a named relationship.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | Source entity set |
id |
string (UUID) |
✓ | Source record GUID |
relationshipName |
string |
✓ | Relationship schema name |
relatedEntitySetName |
string |
✓ | Related entity set |
relatedId |
string (UUID) |
✓ | Related record GUID |
"Associate contact c1d2e3f4 with account a1b2c3d4"
Removes an existing association. relatedId / relatedEntitySetName required for N:N.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | Source entity set |
id |
string (UUID) |
✓ | Source record GUID |
relationshipName |
string |
✓ | Relationship schema name |
relatedId |
string (UUID) |
— | Required for N:N |
relatedEntitySetName |
string |
— | Required for N:N |
"Remove the association between account a1b2c3d4 and contact c1d2e3f4"
Associates one source record with multiple related records at once via a named relationship, executing all associations in parallel. Unlike dataverse_associate (one pair at a time), this accepts an array of related IDs. Uses Promise.allSettled semantics — individual failures are reported per item without aborting the others.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | Source entity set name |
id |
string (UUID) |
✓ | Source record GUID |
relationshipName |
string |
✓ | Relationship schema name |
relatedEntitySetName |
string |
✓ | Related entity set name |
relatedIds |
string[] |
✓ | GUIDs of records to associate (1–200) |
"Associate accounts a1b2, a3b4, and a5b6 with campaign record c1d2e3"
Reads existing N:N associations for a record by querying through a navigation property. Returns the related records — use to verify what is already linked before calling dataverse_associate or dataverse_disassociate.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | Source entity set name, e.g. roles |
id |
string (UUID) |
✓ | Source record GUID |
navigationProperty |
string |
✓ | Navigation property name, e.g. roleprivileges_association |
select |
string |
– | Comma-separated columns to return on related records |
top |
number |
– | Max records to return (default 50, max 1000) |
filter |
string |
– | OData $filter expression applied to related records |
"Check which privileges are linked to role r1a2b3c4 via the roleprivileges_association nav property"
Executes a global (unbound) Dataverse action — state-changing, not tied to a specific record.
| Parameter | Type | Req | Notes |
|---|---|---|---|
actionName |
string |
✓ | Action logical name (e.g. "WinOpportunity") |
parameters |
object |
— | Action parameters (default {}) |
"Execute the WinOpportunity action"
Executes a global (unbound) OData function — read-only, no side effects.
| Parameter | Type | Req | Notes |
|---|---|---|---|
functionName |
string |
✓ | e.g. "RetrieveTotalRecordCount" |
parameters |
object |
— | Key-value pairs serialized into URL |
"Get total record count for the account entity"
Executes an action bound to a specific record. Do not include the Microsoft.Dynamics.CRM. namespace prefix.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
id |
string (UUID) |
✓ | Record GUID |
actionName |
string |
✓ | Action name (no namespace prefix) |
parameters |
object |
— | Action parameters |
"Qualify the lead l1m2n3o4 in Dataverse"
Executes a read-only function bound to a specific record (e.g. CalculateRollupField).
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
id |
string (UUID) |
✓ | Record GUID |
functionName |
string |
✓ | Bound function name |
parameters |
object |
— | Key-value pairs serialized into URL |
"Calculate the rollup field 'totalrevenue' on account a1b2c3d4"
Lists workflows, flows, business rules, and custom actions that reference a table. Use before modifying or removing a table.
| Parameter | Type | Req | Notes |
|---|---|---|---|
tableName |
string |
✓ | Table logical name |
componentType |
string[] |
— | Filter: Workflow, Flow, BusinessRule, Action, BusinessProcessFlow, Plugin, CustomAPI |
"What workflows and flows reference the account table?"
Returns solution components that would block deletion of a component. Use before deleting customizations.
| Parameter | Type | Req | Notes |
|---|---|---|---|
componentType |
number |
✓ | Type code (1=Entity, 2=Attribute, 29=Workflow, 90=PluginAssembly…) |
objectId |
string (UUID) |
✓ | Component GUID |
"Check dependencies blocking deletion of workflow w1x2y3z4"
Executes up to 1000 operations in a single $batch request. Set useChangeset=true to wrap mutations atomically (all-or-nothing rollback).
| Parameter | Type | Req | Notes |
|---|---|---|---|
requests |
array |
✓ | 1–1000 operation objects |
requests[].method |
"GET"|"POST"|"PATCH"|"DELETE" |
✓ | HTTP method |
requests[].url |
string |
✓ | Relative URL, e.g. "accounts(guid)" |
requests[].body |
object |
— | Body for POST/PATCH |
useChangeset |
boolean |
— | Atomic changeset (default false) |
"Create 3 contacts in a single atomic batch"
{ "results": [...], "count": 3 }Delta-query for incremental sync. Pass deltaToken: null for initial snapshot; use returned nextDeltaToken for subsequent calls. Requires change tracking enabled on the table.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
deltaToken |
string|null |
✓ | null for initial sync |
select |
string[] |
— | Columns to return |
"Get all changes to accounts since my last sync (token: abc123)"
{ "newAndModified": [...], "deleted": [{"id":"..."}], "nextDeltaToken": "12345!..." }Publishes unpublished customizations. Omit components to publish all (equivalent to "Publish All" in maker portal). Can take 30–120 s in large environments.
| Parameter | Type | Req | Notes |
|---|---|---|---|
components.entities |
string[] |
— | Entity logical names |
components.webResources |
string[] |
— | Web resource names |
components.optionSets |
string[] |
— | Global option set names |
"Publish all pending customizations"
Creates a model-driven app sitemap (navigation structure) by generating valid sitemap XML and posting it to the Dataverse sitemaps entity set. Optionally links the sitemap to an existing model-driven app module.
| Parameter | Type | Req | Notes |
|---|---|---|---|
sitemapName |
string |
✓ | Display name of the sitemap |
appModuleUniqueName |
string |
— | Unique name of the model-driven app to link this sitemap to |
areas |
array |
✓ | One or more navigation areas (each with title, groups[]) |
Each area contains groups, each group contains subareas with optional entityLogicalName, url, title, and id.
"Create a sitemap with a 'Sales' area containing an 'Accounts' subarea for entity 'account'"
Executes any other tool on behalf of a different Dataverse user by injecting MSCRMCallerId. Applies only to the single wrapped call; cleaned up in finally. Requires prvActOnBehalfOfAnotherUser.
| Parameter | Type | Req | Notes |
|---|---|---|---|
callerId |
string (UUID) |
✓ | Azure AD Object ID of the user to impersonate |
toolName |
string |
✓ | MCP tool name (e.g. "dataverse_create") |
toolArgs |
object |
✓ | Arguments for the wrapped tool |
"Create a contact as user [email protected] (ID: u1v2w3x4-...)"
{
"impersonatedAs": "u1v2w3x4-...",
"tool": "dataverse_create",
"result": { "id": "..." }
}Lists all public SDK messages (custom APIs) registered in the environment.
| Parameter | Type | Req | Notes |
|---|---|---|---|
top |
number |
— | Default 100, max 500 |
nameFilter |
string |
— | Substring match on message name |
"List all custom actions registered in the environment"
{
"total": 5,
"messages": [
{ "name": "new_MyAction", "category": "", "asyncSupported": true }
]
}Lists plugin step registrations (SdkMessageProcessingStep): assembly, message, entity, stage (pre/post), mode (sync/async), and enabled state.
| Parameter | Type | Req | Notes |
|---|---|---|---|
top |
number |
— | Default 100, max 500 |
activeOnly |
boolean |
— | Default true |
entityLogicalName |
string |
— | Filter by entity |
"Show me all active plugin steps for the account entity"
Activates or deactivates a classic Dataverse workflow (statecode/statuscode update).
| Parameter | Type | Req | Notes |
|---|---|---|---|
workflowId |
string (UUID) |
✓ | Workflow GUID |
activate |
boolean |
✓ | true = Activated, false = Draft |
"Activate workflow w1x2y3z4"
{
"workflowId": "...",
"newState": "Activated",
"statecode": 1,
"statuscode": 2
}Lists connection references used in solutions (Power Automate connectors).
| Parameter | Type | Req | Notes |
|---|---|---|---|
top |
number |
— | Default 50, max 200 |
nameFilter |
string |
— | Substring match on display name |
"List all SharePoint connection references in my environment"
Retrieves an environment variable's definition (type, default value) and current override value.
| Parameter | Type | Req | Notes |
|---|---|---|---|
schemaName |
string |
✓ | Schema name, e.g. "new_MyConfig" |
"What is the current value of environment variable new_ApiEndpoint?"
{
"schemaName": "new_ApiEndpoint",
"typeName": "String",
"defaultValue": "https://...",
"currentValue": "https://override...",
"effectiveValue": "https://override..."
}Sets or updates an environment variable's current value (creates or updates the value record).
| Parameter | Type | Req | Notes |
|---|---|---|---|
schemaName |
string |
✓ | Schema name of the environment variable |
value |
string |
✓ | New value to set |
"Set environment variable new_FeatureFlag to 'true'"
Creates a new Dataverse environment variable definition and sets its initial value. Use when the variable does not yet exist.
| Parameter | Type | Req | Notes |
|---|---|---|---|
schemaName |
string |
✓ | Schema name (publisher prefix required, e.g. new_MyVar) |
displayName |
string |
✓ | Human-readable label |
type |
"String"|"Integer"|"Boolean"|"JSON" |
✓ | Variable data type |
value |
string |
✓ | Initial value |
description |
string |
— | Optional description |
defaultValue |
string |
— | Optional default value |
confirm |
true |
✓ | Explicit confirmation required |
"Create environment variable new_MaxRetries of type Integer with value 3"
Returns a comprehensive snapshot of the Dataverse environment: identity (WhoAmI), organization settings (name, version, language, audit config), unmanaged solution count, and environment variable count. Use at the start of a session to orient yourself to the environment and its configuration.
| Parameter | Type | Req | Notes |
|---|---|---|---|
| (none) | No parameters required |
"Give me an overview of this Dataverse environment"
Retrieves plugin execution trace logs: type name, triggering message, entity, duration, trace output, and exception details. Requires Plugin Trace Log enabled in Dataverse settings.
| Parameter | Type | Req | Notes |
|---|---|---|---|
top |
number |
— | Default 50, max 200 |
pluginTypeFilter |
string |
— | Substring match on type name |
messageFilter |
string |
— | e.g. "Create", "Update" |
entityFilter |
string |
— | Entity logical name |
exceptionsOnly |
boolean |
— | Only traces with exceptions (default false) |
"Show me recent plugin failures on the account table"
Retrieves AsyncOperation records for background/classic workflow executions. Not for modern cloud flows (use Power Automate portal for those).
| Parameter | Type | Req | Notes |
|---|---|---|---|
top |
number |
— | Default 50, max 200 |
failedOnly |
boolean |
— | Only failed executions (default false) |
entityFilter |
string |
— | Filter by regarding entity type |
"Show me failed classic workflows for the last 50 executions"
Full-text Relevance Search across all configured Dataverse tables. Returns ranked results with entity name, record ID, score, highlights, and matched fields. Uses the Search API v2.0 endpoint. Requires Relevance Search enabled in Dataverse admin. If Relevance Search is disabled or no entities are configured for search, returns a structured error with errorCategory: "ENV_LIMITATION" and setup instructions.
| Parameter | Type | Req | Notes |
|---|---|---|---|
query |
string |
✓ | Search string; Lucene syntax with searchType=full |
entities |
string[] |
— | Restrict to specific tables |
top |
number |
— | Default 10, max 50 |
searchMode |
"any"|"all" |
— | Match any/all terms (default "any") |
searchType |
"simple"|"full" |
— | Default "simple" |
filter |
string |
— | OData $filter on results |
facets |
string[] |
— | Fields for faceted counts |
orderby |
string[] |
— | Sort fields, e.g. ["@search.score desc"] |
select |
string[] |
— | Fields to return per result |
"Find all records mentioning 'Contoso' across accounts and contacts"
{
"totalRecordCount": 12,
"results": [{ "entityName": "account", "objectId": "...", "score": 0.9 }]
}Retrieves audit log entries with operation type, user info, and parsed change data. At least one filter is recommended. Requires auditing enabled on the environment and table.
| Parameter | Type | Req | Notes |
|---|---|---|---|
recordId |
string (UUID) |
— | Specific record GUID |
entityLogicalName |
string |
— | Filter by entity type |
userId |
string (UUID) |
— | Filter by user |
fromDate |
string |
— | ISO 8601 date (entries on/after) |
top |
number |
— | Default 50, max 500 |
operations |
string[] |
— | "Create", "Update", "Delete", "Activate", "Deactivate", "Share", "Assign", "Access" |
"Show me all updates to account a1b2c3d4 in the last week"
Checks prospective record fields against existing records using Dataverse built-in duplicate detection rules.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entityLogicalName |
string |
✓ | Table to check, e.g. "account" |
record |
object |
✓ | Field values of the prospective record |
top |
number |
— | Default 5, max 20 |
"Check if there's already an account named 'Contoso Ltd'"
{
"hasDuplicates": true,
"duplicateCount": 1,
"duplicates": [{ "accountid": "...", "name": "Contoso Ltd" }]
}Retrieves notes and file attachments linked to a record. Set includeContent=true to fetch base64 file bodies (can be very large).
| Parameter | Type | Req | Notes |
|---|---|---|---|
recordId |
string (UUID) |
✓ | Parent record GUID |
includeContent |
boolean |
— | Include documentBody (default false) |
top |
number |
— | Default 20, max 100 |
mimeTypeFilter |
string |
— | e.g. "application/pdf" |
"Get all notes attached to account a1b2c3d4"
Creates a note or file attachment linked to a Dataverse record. Provide noteText for a text note, documentBody (base64) for a file, or both.
| Parameter | Type | Req | Notes |
|---|---|---|---|
recordId |
string (UUID) |
✓ | Parent record GUID |
entitySetName |
string |
✓ | Parent entity set, e.g. "accounts" |
noteText |
string |
— | Text content (required if no documentBody) |
subject |
string |
— | Note subject/title |
fileName |
string |
— | File name (for attachments) |
mimeType |
string |
— | MIME type, e.g. "application/pdf" |
documentBody |
string |
— | Base64-encoded file content (required if no noteText) |
"Attach a PDF report to account a1b2c3d4"
Searches Dataverse system users by name or email. At least one of search or businessUnitId is required. Excludes application users and disabled users by default.
| Parameter | Type | Req | Notes |
|---|---|---|---|
search |
string |
✓* | Full-name or email contains-search (one of these required) |
businessUnitId |
string (UUID) |
✓* | Restrict to a business unit |
includeDisabled |
boolean |
— | Default false |
includeApplicationUsers |
boolean |
— | Default false |
top |
number |
— | Default 20, max 100 |
"Find all users named 'John' in my environment"
Returns all security roles assigned to a system user.
| Parameter | Type | Req | Notes |
|---|---|---|---|
userId |
string (UUID) |
✓ | System user GUID |
"What security roles does user u1v2w3x4 have?"
{
"userId": "...",
"fullname": "John Doe",
"roles": [{ "name": "Sales Manager", "roleId": "..." }],
"roleCount": 1
}Lists saved (system) and optionally personal views for a Dataverse table, including view name, ID, default flag, query type, and description.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entityLogicalName |
string |
✓ | Table logical name, e.g. "account" |
includePersonal |
boolean |
— | Include personal views (default false) |
top |
number |
— | Max per category, default 20, max 100 |
"List all system views for the account table"
{
"entityLogicalName": "account",
"systemViews": [
{ "id": "...", "name": "Active Accounts", "isDefault": true }
],
"systemViewCount": 5
}Uploads a file to a Dataverse file or image column on a record. File content must be base64-encoded.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
recordId |
string (UUID) |
✓ | Record GUID |
columnName |
string |
✓ | File column logical name (alphanumeric/underscore only) |
fileContent |
string |
✓ | Base64-encoded file content |
fileName |
string |
✓ | File name including extension, e.g. "report.pdf" |
"Upload report.pdf to the attachment column on account a1b2c3d4"
{
"success": true,
"recordId": "...",
"columnName": "new_report",
"fileName": "report.pdf",
"sizeBytes": 204800
}Downloads a file from a Dataverse file or image column. Returns the file as a base64-encoded string with its name and size.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entitySetName |
string |
✓ | OData entity set name |
recordId |
string (UUID) |
✓ | Record GUID |
columnName |
string |
✓ | File column logical name |
"Download the attachment from account a1b2c3d4 column new_report"
{
"fileName": "report.pdf",
"sizeBytes": 204800,
"contentBase64": "JVBERi0x..."
}Lists business units in the environment with name, ID, parent BU ID, disabled status, and creation date.
| Parameter | Type | Req | Notes |
|---|---|---|---|
top |
number |
— | Default 50, max 200 |
includeDisabled |
boolean |
— | Include disabled BUs (default false) |
"List all active business units in my Dataverse environment"
Lists Dataverse teams (owner teams and access teams) within one or all business units.
| Parameter | Type | Req | Notes |
|---|---|---|---|
top |
number |
— | Default 50, max 200 |
teamType |
"Owner"|"Access"|"AAD" |
— | Filter by team type; omit for all |
businessUnitId |
string (UUID) |
— | Filter by business unit |
"List all owner teams in the environment"
Lists security roles in the environment, optionally filtered by name.
| Parameter | Type | Req | Notes |
|---|---|---|---|
nameFilter |
string |
— | Substring match on role name |
top |
number |
— | Default 50, max 200 |
"List all security roles that contain 'Sales'"
{
"total": 3,
"roles": [{ "roleId": "...", "name": "Salesperson", "businessUnitId": "..." }]
}Assigns a security role to a system user (idempotent — returns "already_assigned" if the role is already assigned).
| Parameter | Type | Req | Notes |
|---|---|---|---|
userId |
string (UUID) |
✓ | System user GUID |
roleId |
string (UUID) |
✓ | Security role ID |
"Assign role r1s2t3u4 to user u1v2w3x4"
Removes a security role from a system user.
| Parameter | Type | Req | Notes |
|---|---|---|---|
userId |
string (UUID) |
✓ | System user GUID |
roleId |
string (UUID) |
✓ | Security role ID |
"Remove role r1s2t3u4 from user u1v2w3x4"
Assigns a security role to a Dataverse team. All team members inherit the role permissions.
| Parameter | Type | Req | Notes |
|---|---|---|---|
teamId |
string (UUID) |
✓ | Team GUID |
roleId |
string (UUID) |
✓ | Security role GUID |
confirm |
true |
✓ | Explicit confirmation required |
"Assign role r1s2t3u4 to team t1e2a3m4"
Retrieves all privileges assigned to a security role with their depth levels (None/Basic/Local/Deep/Global). Use to audit a role's current permissions before modifying them, or to verify depth assignments.
| Parameter | Type | Req | Notes |
|---|---|---|---|
roleId |
string (UUID) |
✓ | GUID of the security role |
"What privileges does role r1s2t3u4 currently have?"
Adds one or more privileges to a security role with specified depth levels. Supports all depths: None, Basic (user-level), Local (BU-level), Deep (parent-BU), Global (org-level). For org-owned entities only Global is valid.
| Parameter | Type | Req | Notes |
|---|---|---|---|
roleId |
string (UUID) |
✓ | GUID of the security role |
privileges |
array |
✓ | Array of { privilegeId, depth, businessUnitId? } entries (1–N) |
privileges[].privilegeId |
string (UUID) |
✓ | GUID — query privileges entity to find by name or entity |
privileges[].depth |
string |
✓ | None, Basic, Local, Deep, or Global |
privileges[].businessUnitId |
string (UUID) |
— | Defaults to root BU if omitted |
"Add prvReadAccount with Global depth to role r1s2t3u4"
Atomically replaces all privileges on a security role using the ReplacePrivilegesRole action. The existing privilege set is completely overwritten. Use dataverse_add_role_privileges instead if only additive changes are needed.
| Parameter | Type | Req | Notes |
|---|---|---|---|
roleId |
string (UUID) |
✓ | GUID of the security role |
privileges |
array |
✓ | Complete new privilege set (same schema as add_role_privileges) |
confirm |
true |
✓ | Required — replaces all existing privileges on the role |
"Replace all privileges on role r1s2t3u4 with a custom set"
Lists classic Dataverse workflows and modern cloud flows registered in the environment.
| Parameter | Type | Req | Notes |
|---|---|---|---|
top |
number |
— | Default 50, max 200 |
activeOnly |
boolean |
— | Return only activated workflows (default false) |
nameFilter |
string |
— | Substring match on workflow name |
"List all active workflows on the account table"
Retrieves a single workflow definition by ID, including its trigger, steps, and current state.
| Parameter | Type | Req | Notes |
|---|---|---|---|
workflowId |
string (UUID) |
✓ | Workflow GUID |
"Get the definition of workflow w1x2y3z4"
Lists available built-in guides that walk through common multi-step Dataverse tasks.
| Parameter | Type | Req | Notes |
|---|---|---|---|
| — | — | — | No parameters |
"What guides are available in this MCP server?"
Retrieves the full step-by-step content for a specific guide by name.
| Parameter | Type | Req | Notes |
|---|---|---|---|
guideName |
string |
✓ | Guide name from list_guides |
"Show me the steps for the entity-audit guide"
Returns a ranked list of MCP tools relevant to a natural-language task description. Use this when unsure which tool to call — it uses tag-based matching to surface the right tools.
| Parameter | Type | Req | Notes |
|---|---|---|---|
task |
string |
✓ | Natural-language description of the task |
top |
number |
— | Max results (default 5) |
"Which tool should I use to create a new lookup column?"
Lists all available tool tags with the number of tools in each category. Use this to discover what kinds of operations are available before calling dataverse_suggest_tools.
| Parameter | Type | Req | Notes |
|---|---|---|---|
| — | — | — | No parameters |
"What categories of tools are available in this MCP server?"
Attribute tools manage column-level schema in Dataverse tables. All write operations require confirm: true and auto-publish the entity definition by default.
Creates a new column on an existing Dataverse table. Supports 11 attribute types with type-specific parameters.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entityLogicalName |
string |
✓ | Target table (e.g. "account") |
schemaName |
string |
✓ | Must include publisher prefix (e.g. "new_CustomField") |
attributeType |
"String"|"Memo"|"Integer"|"Decimal"|"Money"|"DateTime"|"Boolean"|"Picklist"|"MultiSelectPicklist"|"AutoNumber"|"Image" |
✓ | Column type |
displayName |
string |
✓ | Human-readable label |
description |
string |
— | Column description |
requiredLevel |
"None"|"ApplicationRequired"|"Recommended" |
— | Requirement level (default "None") |
maxLength |
number |
— | String/Memo max chars |
minValue/maxValue |
number |
— | Integer/Decimal range bounds |
precision |
number |
— | Decimal/Money decimal places |
dateTimeFormat |
"DateOnly"|"DateAndTime" |
— | DateTime display format |
defaultBooleanValue |
boolean |
— | Default for Boolean columns |
picklistOptions |
{value: number, label: string}[] |
— | Option values for Picklist/MultiSelectPicklist |
autoNumberFormat |
string |
— | Format string for AutoNumber, e.g. "INV-{SEQNUM:5}" |
languageCode |
number |
— | Label language code (default 1033 = English) |
autoPublish |
boolean |
— | Publish after create (default true) |
confirm |
true |
✓ | Must be true |
"Add a text column 'new_ExternalId' to the account table with max 100 characters"
{
"logicalName": "new_externalid",
"schemaName": "new_ExternalId",
"attributeType": "String",
"entityLogicalName": "account",
"published": true
}Updates properties of an existing column. Only columns with IsCustomizable = true can be modified.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entityLogicalName |
string |
✓ | Table containing the column |
attributeLogicalName |
string |
✓ | Column logical name (e.g. "new_myfield") |
displayName |
string |
— | New display label |
description |
string |
— | New description |
requiredLevel |
"None"|"ApplicationRequired"|"Recommended" |
— | New requirement level |
maxLength |
number |
— | Increase only (cannot decrease) |
isSearchable |
boolean |
— | Include in Quick Find views |
languageCode |
number |
— | Default 1033 |
autoPublish |
boolean |
— | Default true |
confirm |
true |
✓ | Must be true |
"Update new_externalid on account to be required"
| Parameter | Type | Req | Notes |
|---|---|---|---|
entityLogicalName |
string |
✓ | Table containing the column |
attributeLogicalName |
string |
✓ | Column logical name (must be a custom column) |
autoPublish |
boolean |
— | Publish after delete (default true) |
confirm |
true |
✓ | Must be true |
"Delete the column new_externalid from account"
Creates a lookup (N:1) column on a table, simultaneously defining a 1:N relationship between two tables. This is the correct way to add a foreign-key-style reference to another table.
| Parameter | Type | Req | Notes |
|---|---|---|---|
entityLogicalName |
string |
✓ | Table that will contain the lookup column (the "many" side) |
schemaName |
string |
✓ | Must include publisher prefix (e.g. "new_ParentAccount") |
displayName |
string |
✓ | Human-readable label |
referencedEntity |
string |
✓ | Table being looked up (the "one" side, e.g. "account") |
description |
string |
— | Column description |
requiredLevel |
"None"|"ApplicationRequired"|"Recommended" |
— | Default "None" |
languageCode |
number |
— | Default 1033 |
autoPublish |
boolean |
— | Default true |
confirm |
true |
✓ | Must be true |
"Add a lookup to 'account' on the contact table called new_PrimaryAccount"
{
"lookupLogicalName": "new_primaryaccount",
"relationshipSchemaName": "new_contact_primaryaccount",
"referencedEntity": "account",
"referencingEntity": "contact",
"published": true
}All tool handlers return { isError: true, content: [{ type: "text", text: "Error: ..." }] } on failure. Zod input validation runs before any network call.
| Status | Behavior | Attempts |
|---|---|---|
| 401 | Invalidate token, retry once with fresh token | 1 |
| 429 / 503 / 504 | Exponential backoff (2^attempt × 1000ms) |
maxRetries (default 3) |
| Other | Throw immediately | 0 |
Dataverse error bodies are formatted as Dataverse error <code>: <message>. Timeouts (ECONNABORTED) produce Request timed out. Check your Dataverse environment URL.
Certain tools include an errorCategory field in the error text when the failure has a well-known cause:
errorCategory |
Meaning | Example |
|---|---|---|
ENV_LIMITATION |
Feature not enabled or unavailable in this environment | dataverse_search when Relevance Search is disabled |
PERMISSIONS |
Operation denied due to insufficient privileges | Restricted table or action |
SCHEMA_MISMATCH |
Supplied data conflicts with the table's metadata schema | Wrong attribute type in dataverse_create_attribute |
| Mode | Flow | Use Case |
|---|---|---|
| Device Code | MSAL Public Client → device code + silent refresh | Local dev, interactive |
clientSecretis never logged or returned in tool responses.- Token cache is encrypted (AES-256-GCM) at
~/.mcp-dataverse/and should not be shared. - OData path segments use
esc()(single-quote doubling) to prevent OData injection. columnNamein file tools is validated against/^[a-zA-Z0-9_]+$/to prevent path traversal.MSCRMCallerIdfor impersonation is set per-call and cleaned up in afinallyblock regardless of outcome..msal-cache.jsonshould be in.gitignore. When running in HTTP mode, ensure the server is not exposed on a public network without proper auth.
| Limitation | Details |
|---|---|
| Transport | stdio (default) and HTTP/SSE. stdio: spawned as child process. HTTP: run as standalone service on configurable port. |
| Single environment | One Dataverse environment per server instance. Restart to switch. |
| No streaming | Responses are complete JSON. Very large result sets may exceed AI model context limits. |
| No real-time subscriptions | Use dataverse_change_detection for polling-based incremental sync. |
| Limitation | Details |
|---|---|
$top max |
dataverse_query caps at 5000 per call. Use dataverse_retrieve_multiple_with_paging for more. |
| Paging max | dataverse_retrieve_multiple_with_paging caps at 50,000 records total. |
| FetchXML entity set | Auto-extraction appends "s" to the logical name. Non-standard entity set names require explicit entitySetName. |
| Limitation | Details |
|---|---|
| UUID required for get/update/delete | Alternate-key retrieval via dataverse_get is not supported; use dataverse_upsert or dataverse_query instead. |
| ETag conditional update | dataverse_update supports optional etag parameter for optimistic concurrency (If-Match: <etag>). When omitted, sends If-Match: *. |
| Limitation | Details |
|---|---|
| Token expiry | If the refresh token expires (~90 days), re-run npm run auth:setup. |
| Limitation | Details |
|---|---|
Plugin/CustomAPI in list_dependencies |
Only Workflow/BusinessRule/Flow types fully supported. Plugin step queries require separate SDK message lookups not yet implemented. |
solutionName in dependency results |
Always null — solution join not yet implemented. |
| Limitation | Details |
|---|---|
| Max operations | 1,000 per batch (Zod-enforced). |
No $<Content-ID> references |
Cross-referencing created entities within a changeset is not supported at the tool level. |
This document reflects the MCP Dataverse server codebase as of v0.5.0 — 73 tools across 25 categories.