New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@slamb2k/dvx

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@slamb2k/dvx

Agent-first CLI and MCP server for Microsoft Dataverse CE/Sales/Service

latest
npmnpm
Version
1.0.7
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created
Source

dvx

Agent-first CLI and MCP server for Microsoft Dataverse (CE / Sales / Service).

dvx treats the Dataverse Web API the way gws treats Google Workspace — a single binary with a dual surface (CLI + MCP stdio) that derives its capabilities at runtime from the API's own schema. No hand-authored tool lists, no hardcoded entity definitions, no 20-row ceilings.

Why dvx?

Dataverse is a uniquely hostile API for AI agents:

  • Opaque GUIDs everywhere — every entity, relationship, and option set is a UUID with no human-readable context
  • Enormous, per-org $metadata — the OData metadata document can exceed 50MB, and every org's schema is different
  • Polymorphic lookups — a single lookup field can reference multiple entity types
  • Invisible business logic — server-side plugins, workflows, and business rules execute silently on write operations
  • Complex batch format — OData $batch uses multipart MIME boundaries with changeset semantics

Microsoft's official Dataverse MCP Server takes a static approach: it pre-registers tools and caps query results at 20 rows with no pagination. dvx takes the opposite approach — it discovers the schema at runtime and streams results without artificial limits.

For a detailed comparison with use cases across 9 domains, see docs/comparison-vs-official-mcp.md.

Install

# npm (all platforms)
npm install -g dvx

# Linux binary (x64)
curl -fsSL https://raw.githubusercontent.com/slamb2k/dvx/main/scripts/install.sh | sh

macOS users: install via npm. Pre-built macOS binaries are not currently published.

Quick Start

1. Create an auth profile

# Service principal (non-interactive, CI/CD)
dvx auth create \
  --name myorg \
  --environment-url https://myorg.crm.dynamics.com \
  --tenant-id <tenant-id> \
  --client-id <client-id> \
  --client-secret <secret>

# Delegated (interactive browser login)
dvx auth login \
  --name myorg \
  --environment-url https://myorg.crm.dynamics.com \
  --tenant-id <tenant-id> \
  --client-id <client-id>

2. Query data

# List all entities
dvx entities

# Show schema for an entity
dvx schema account

# OData query
dvx query --odata '/accounts?$select=name,revenue&$top=10'

# FetchXML query
dvx query --fetchxml '<fetch top="10"><entity name="account"><attribute name="name"/></entity></fetch>'

# From file (auto-detects OData vs FetchXML)
dvx query --file my-query.xml --output ndjson

3. Mutate records

# Create
dvx create account --json '{"name": "Contoso Ltd", "revenue": 1000000}'

# Update
dvx update account 00000000-0000-0000-0000-000000000001 \
  --json '{"revenue": 2000000}'

# Upsert (match on a field)
dvx upsert account --match-field name \
  --json '{"name": "Contoso Ltd", "revenue": 2000000}'

# Delete
dvx delete account 00000000-0000-0000-0000-000000000001 --confirm

# All mutations support --dry-run
dvx create account --json '{"name": "Test"}' --dry-run

4. Batch operations

# From a JSON file of operations
dvx batch --file operations.json

# Atomic (wrapped in OData changeset)
dvx batch --file operations.json --atomic

Batch input format:

[
  { "method": "POST", "path": "/accounts", "body": { "name": "Acme" } },
  { "method": "PATCH", "path": "/accounts(00000000-...)", "body": { "revenue": 500000 } }
]

5. Execute custom actions

# Global action
dvx action WinOpportunity --json '{"Status": 3, "OpportunityClose": {...}}'

# Bound action
dvx action QualifyLead --entity lead --id 00000000-... --json '{...}'

6. Interactive demo

dvx demo walks through dvx's differentiators with live Dataverse calls, comparison callouts, and auto-cleanup.

# Interactive tier selection (prompts if TTY)
dvx demo

# Non-interactive — specify tier directly
dvx demo --tier read    # Schema discovery, OData, FetchXML — no data changes
dvx demo --tier write   # Read + CRUD lifecycle with [dvx-demo] prefix, auto-cleanup
dvx demo --tier full    # Write + batch, WhoAmI action, impersonation, aggregation

Each step prints a comparison callout showing what native Dataverse MCP and PAC CLI cannot do. A summary table with pass/skip/fail status and elapsed times is printed at the end.

MCP Server

dvx exposes a Model Context Protocol server for AI agent integration.

# stdio transport (default — for Claude Desktop, Cursor, etc.)
dvx mcp --entities account,contact,opportunity

# HTTP transport (for remote/multi-session deployments)
dvx mcp --transport http --port 3000 --entities account,contact

Meta-tools (always available)

ToolDescription
list_entitiesList all entity logical names in the org
discover_entityFetch full schema for an entity (attributes, types, relationships)
execute_queryRun OData or FetchXML queries with full pagination
execute_actionExecute any global or bound Dataverse action
batch_executeRun multiple operations in a single request, optionally atomic

Meta-tools solve the MCP dictionary problem — instead of registering hundreds of tools upfront (one per entity), agents discover entities on-demand and use generic query/mutation tools. This keeps the tool list small and the agent's context window clean.

Dynamic entity tools (per --entities scope)

When you pass --entities account,contact, dvx generates 4 typed tools per entity:

  • create_account / create_contact
  • update_account / update_contact
  • get_account / get_contact
  • query_account / query_contact

These provide typed input schemas derived from the entity's actual attributes — an agent can see exactly which fields exist, their types, and which are required.

Claude Desktop configuration

{
  "mcpServers": {
    "dataverse": {
      "command": "dvx",
      "args": ["mcp", "--entities", "account,contact,opportunity,lead"]
    }
  }
}

Authentication

dvx supports three authentication patterns:

PatternUse CaseFlow
Service PrincipalCI/CD, server-to-server, MCP serverClient credentials (ConfidentialClientApplication)
Delegated (PKCE)Interactive CLI use, per-user contextBrowser-based OAuth with PKCE (PublicClientApplication)
ImpersonationService principal acting as a specific user--as-user <EntraObjectId> adds CallerObjectId header

Secrets are never written to disk. Service principal client secrets are passed via environment variables. Delegated tokens are cached in .dvx/msal-cache.json (mode 0600).

# Manage profiles
dvx auth list
dvx auth select myorg

# Impersonate a user (requires prvActOnBehalfOfAnotherUser privilege)
dvx create account --json '{"name": "Test"}' --as-user 00000000-...

Key Features

  • Runtime schema discovery — entity definitions fetched from EntityDefinitions API, never hardcoded
  • SQLite schema cache — persistent cache with configurable TTL (default 5 min), survives restarts
  • FetchXML with auto-pagination — paging cookies handled transparently
  • NDJSON streaming — page through results emitting one record per line, no memory buffering
  • Retry with backoff — automatic retry on 429/5xx with Retry-After header support
  • Dry-run on all mutations — --dry-run prints what would execute without sending
  • Field masking — --fields or $select on all queries, never returns full records by default
  • Batch operations — up to 1000 ops per request with optional atomic changesets
  • Input validation — GUIDs, entity names, action names, and URLs validated before any HTTP call
  • Typed errors — full error hierarchy (DvxError → AuthError, DataverseError, ValidationError, etc.)

Configuration

Environment variables

# Required
DATAVERSE_URL=https://yourorg.crm.dynamics.com
DATAVERSE_CLIENT_ID=<app-registration-client-id>
DATAVERSE_CLIENT_SECRET=<from-keychain-or-env>
DATAVERSE_TENANT_ID=<entra-tenant-id>

# Optional
DVX_SCHEMA_CACHE_TTL_MS=300000    # Schema cache TTL (default: 5 min)
DVX_SCHEMA_CACHE_PATH=.dvx/cache.db  # SQLite cache location
DVX_MAX_ROWS=5000                 # Per-query row cap
DVX_DEBUG=true                    # Verbose HTTP logging

Local files (managed by dvx)

FilePurpose
.dvx/config.jsonAuth profiles (no secrets)
.dvx/msal-cache.jsonMSAL delegated token cache (0600)
.dvx/cache.dbSQLite schema cache

Architecture

┌──────────────┐     ┌──────────────┐
│  CLI (human) │     │  MCP (agent) │
└──────┬───────┘     └──────┬───────┘
       │                    │
       └────────┬───────────┘
                │
       ┌────────▼────────┐
       │  DataverseClient │   ← single client, all operations
       ├─────────────────┤
       │  AuthManager     │   ← service principal or PKCE
       │  SchemaCache     │   ← SQLite-backed, TTL-based
       │  withRetry()     │   ← 429/5xx backoff
       └────────┬────────┘
                │
       ┌────────▼────────┐
       │  Dataverse       │
       │  Web API         │
       └─────────────────┘

All operations flow through a single DataverseClient class. No direct HTTP calls in command handlers or MCP tools. Schema is always fetched live or from cache — never hardcoded.

Comparison with Microsoft's Official Dataverse MCP Server

See docs/comparison-vs-official-mcp.md for a detailed feature comparison and use cases across Sales, Customer Service, Field Service, Marketing, Finance, ALM, Data Migration, Security, and Reporting.

Key differences at a glance:

CapabilitydvxOfficial Dataverse MCP
Query row limit5,000 (configurable)20 rows, hard-coded
PaginationFull (OData + FetchXML)None
FetchXMLFull with auto-pagingNot supported
Batch operations$batch with changesetsNot supported
Custom actionsexecute_actionNot supported
ImpersonationCallerObjectId headerNot supported
Schema discoveryRuntime via EntityDefinitionsStatic tool list
Dry-runAll mutationsNot supported
NDJSON streamingYesNo
CLI interfaceFull featuredMCP only

License

MIT

Keywords

dataverse

FAQs

Package last updated on 10 Mar 2026

Related posts