Skip to main content

dv-connect

One-step setup and connection diagnostics for a Dataverse environment — installs tools, authenticates, registers MCP, writes `.env`, and verifies active profiles and linked ERP endpoints. Use when starting a new project, switching environments, fixing authentication, troubleshooting MCP, or checking existing Dataverse / Finance and Operations connectivity or linkage.

Source facts

Repository
microsoft/Dataverse-skills
Last source activity
October 12, 2026 at 18:29
Detected SKILL.md language
English
Stars
249
Forks
64

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
6 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
dv-connect
description
One-step setup and connection diagnostics for a Dataverse environment — installs tools, authenticates, registers MCP, writes `.env`, and verifies active profiles and linked ERP endpoints. Use when starting a new project, switching environments, fixing authentication, troubleshooting MCP, or checking existing Dataverse / Finance and Operations connectivity or linkage.
# Skill: Connect One-step, idempotent Dataverse connection. Each step checks if it's already done and skips. > **Environment-First Rule** — All metadata and plugin registrations are created **in the environment** via API/scripts, then pulled into the repo. Never hand-write solution XML to create components. **Execute steps in order; do not skip ahead.** **Exception:** Step 0 can short-circuit the flow if the workspace is already set up. > **Host entry test (FIRST — before Step 0).** A **local Windows/macOS host is capable by default, whichever agent drives it** — it can run the CLIs, use persistent credentials, and host local MCP servers; an approval/sandbox gate isn't a constraint, and a **missing CLI = install it**. **Constrained only when** a runtime **can't start**, auth **can't persist**, or the host is explicitly **ChatGPT Work Mode / Codex cloud / CI / no-keyring Linux** (deterministic table: [headless-hosts.md](references/headless-hosts.md)). **Constrained →** install **only** Python + pip deps, `.env`, `scripts/auth.py`, verify `python scripts/auth.py --check`, **skip** CLI / PAC / MCP. **Capable →** normal flow below. --- ## Step 0: Detect existing setup (run this first) Before touching anything, check whether this workspace is already connected to a Dataverse environment. Repeating setup on an already-configured workspace overwrites `.env`, re-registers MCP, and wastes time. Gemini supports GA only. If Preview is requested, explain and stop before setup shortcuts. Run these checks in order. If **all four pass**, skip straight to Step 7 (final verification) and stop there. 1. **`.env` is present and complete** — file exists at the workspace root and contains non-empty values for `DATAVERSE_URL`, `TENANT_ID`, and `MCP_CLIENT_ID` 2. **MCP is registered** — the host MCP list has a `dataverse-*` entry, or Gemini has its bundled `dataverse` entry, pointing at `DATAVERSE_URL` 3. **Both auth surfaces match `.env`** — `dataverse auth who` shows a profile whose `Environment Url` matches `DATAVERSE_URL`, AND `pac org who` against a PAC profile for the same URL succeeds. (DV CLI auth covers Connect / Data / Query / Metadata / MCP / Python; PAC auth covers `dv-solution` and `dv-admin`. Both are front-loaded at connect time so neither prompts later.) 4. **Python SDK is importable and current** — `python -c "from PowerPlatform.Dataverse.client import DataverseClient; import pandas; from importlib.metadata import version; v=version('PowerPlatform-Dataverse-Client'); parts=tuple(int(p) for p in v.split('.')[:2]); assert parts>=(1,1), f'SDK {v} is outdated, need >=1.1.0'"` exits 0 **If all pass:** First ensure `.env` has valid attribution — set `DATAVERSE_PLUGIN_VERSION` to the loaded manifest `version` and add `DATAVERSE_PLUGIN_AGENT` (detected host, per Step 3) if absent or a stale `unknown`/placeholder. Confirm the detected setup (URL, profile, MCP server), and jump to Step 7. Do not otherwise rewrite `.env`, re-register MCP, or re-run `pip install`. **If any check fails:** Proceed through the normal flow (Steps 1–7), but still use each step's own skip condition. A partially-configured workspace doesn't need a full redo — e.g., if only `.env` and MCP are missing but tools and auth are fine, start at Step 2 or Step 3. --- ## Step 1: Ensure tools are installed Check each tool independently -- report all missing tools at once. See [tools-setup.md](references/tools-setup.md) for install commands. | Tool | Check | |---|---| | Python 3 | `python --version` | | Git | `git --version` | | Node.js | `node --version` | | PAC CLI | `pac` (prints version banner; `pac --version` is not valid) (see [tools-setup.md](references/tools-setup.md) if not in PATH) | | Dataverse CLI | `npm list -g @microsoft/dataverse` | | .NET SDK | `dotnet --version` | | Azure CLI | `az --version` | .NET SDK is needed for PAC CLI but NOT for the Dataverse CLI (the npm package bundles its own runtime). Node.js powers the Dataverse CLI npm package (`@microsoft/dataverse`), which is used as the MCP proxy and for scripted data plane actions. Azure CLI is used as a fallback for environment discovery when PAC CLI isn't available (see [mcp-configuration.md](references/mcp-configuration.md) Step 3b). GitHub CLI is not needed for connecting — it's used later for ALM/CI/CD scenarios (see `dv-solution`). If any tool is missing, install it (see [tools-setup.md](references/tools-setup.md)), then verify. If `winget` installs a tool but it's not in PATH, ask the user to restart the terminal. After Python is confirmed, check if deps are already present before installing: ``` python -c "from PowerPlatform.Dataverse.client import DataverseClient; import azure.identity, msal, msal_extensions, requests, pandas; print('OK')" ``` If it prints `OK`, skip pip. Otherwise: ``` pip install --upgrade azure-identity requests PowerPlatform-Dataverse-Client pandas msal msal-extensions ``` `msal` + `msal-extensions` let `scripts/auth.py` reuse the `dataverse auth create` cache -- one sign-in for CLI, MCP, Python. After Node.js is confirmed, install the Dataverse CLI **only if missing** (do not re-run on every connect -- on managed devices each `@latest` fetch can trigger npm-registry security prompts; see [tools-setup.md](references/tools-setup.md)): ``` npm install -g @microsoft/dataverse@latest ``` **Skip condition:** All tools present, Python SDK installed, and `pandas` importable (`python -c "import pandas"`). --- ## Step 2: Discover and select the environment Before asking the user for a URL, check what's already available. > **Auth tool choice.** Two tools, two AAD apps, two caches — front-load both at connect: > > 1. **`dataverse auth create`** (app `0c412cc3-…`) covers DV CLI + MCP + Python. > 2. **`pac auth create`** (PAC's own app) covers `dv-solution` + `dv-admin`. Check for an existing DV CLI profile first, then fall back to PAC for environment discovery if needed: ``` dataverse auth list dataverse auth who pac auth list # PAC profiles are still useful for env discovery / pac org list ``` **If `dataverse auth who` shows a profile and its environment matches the user's target:** - Reuse it. Set `DATAVERSE_URL` and `TENANT_ID` from the profile. **If no DV CLI profile exists (or it points at the wrong environment):** - Ask: "Do you want to connect to an existing environment or create a new one?" **Before selecting, check for tenant/region mismatch.** If the target URL uses a different region than the authenticated account's environments, create a new profile for the correct tenant rather than reuse the old one: ``` dataverse auth create --environment <url> # interactive (WAM broker on Windows → no browser tab) dataverse auth create --environment <url> --deviceCode # headless / remote / SSH ``` If the user hits an admin-consent error, the CLI prints the correct scope-scoped consent URL to share with a tenant admin — do not synthesize one. **To switch between existing DV CLI profiles:** ``` dataverse auth select --name <profile-name> ``` **To create a new environment** (requires admin permissions): ``` pac admin create --name "<name>" --type "<type>" --region "<region>" ``` If this fails with permissions error, guide the user to [Power Platform Admin Center](https://admin.powerplatform.microsoft.com/) to create it, then connect. **Confirm connection:** ``` dataverse auth who dataverse org who --context "app=dataverse-skills/<ver>;skill=dv-connect;agent=<agent>" ``` Parse the output to extract `DATAVERSE_URL`, `TENANT_ID`, and — on ERP-linked envs — `ERP_URL` (see [`erp-detection.md`](references/erp-detection.md)). If neither command shows a tenant ID, fall back to: ```bash curl -sI https://<org>.crm.dynamics.com/api/data/v9.2/ \ | grep -i "WWW-Authenticate" \ | sed -n 's|.*login\.microsoftonline\.com/\([^/]*\).*|\1|p' ``` ### Step 2b: Front-load PAC CLI auth for the same environment PAC uses its own AAD app, so a separate sign-in is required for `dv-solution` and `dv-admin` — do it now. ``` pac auth list # skip if a profile for $DATAVERSE_URL exists pac auth create --name <orgid> --environment <DATAVERSE_URL> ``` Use the same account as Step 2. If PAC CLI is not installed, skip with a note that `dv-solution` / `dv-admin` will need it later. --- ## Step 3: Create .env Present authentication options: > How would you like to authenticate with Dataverse? > 1. **Interactive login (recommended)** — Sign in via browser. No app registration needed. Token stays cached across sessions. > 2. **CI/CD service principal** — Use `CLIENT_SECRET` or `CLIENT_CERTIFICATE_PATH`. Write `.env` directly — do not instruct the user to create it: Use one detected `tool_type` to derive both `MCP_CLIENT_ID` and canonical attribution. Set `PLUGIN_VERSION` from the loaded manifest; Antigravity uses `.claude-plugin/plugin.json` because native `plugin.json` has none. ```python tool_type = "<copilot | claude | cursor | codex | gemini | antigravity | unknown>" plugin_version = "<plugin manifest version, e.g. 1.5.0>" mcp_client_id = "aebc6443-996d-45c2-90f0-388ff96faa56" if tool_type == "copilot" else "0c412cc3-0dd6-449b-987f-05b053db9457" agent_host = { "copilot": "copilot", "claude": "claude-code", "cursor": "cursor", "codex": "codex", "gemini": "gemini-cli", "antigravity": "antigravity-cli", }.get(tool_type, "unknown") with open(".env", "w") as f: f.write(f"DATAVERSE_URL={dataverse_url}\n") f.write(f"TENANT_ID={tenant_id}\n") f.write(f"MCP_CLIENT_ID={mcp_client_id}\n") f.write(f"DATAVERSE_PLUGIN_VERSION={plugin_version}\n") f.write(f"DATAVERSE_PLUGIN_AGENT={agent_host}\n") f.write(f"SOLUTION_NAME={solution_name}\n") f.write(f"PUBLISHER_PREFIX=\n") # filled in when solution is created f.write(f"PAC_AUTH_PROFILE=nonprod\n") if client_id: f.write(f"CLIENT_ID={client_id}\n") if client_secret: f.write(f"CLIENT_SECRET={client_secret}\n") ``` Ensure `.env` is in `.gitignore`: ```python import os GITIGNORE_ENTRIES = [ ".env", ".vscode/settings.json", ".claude/mcp_settings.json", ".token_cache.bin", ".dataverse/", "*.snk", "__pycache__/", "*.pyc", "solutions/*.zip", "plugins/**/bin/", "plugins/**/obj/", ] gitignore = open(".gitignore").read() if os.path.exists(".gitignore") else "" missing = [e for e in GITIGNORE_ENTRIES if e not in gitignore] if missing: with open(".gitignore", "a") as f: f.write("\n" + "\n".join(missing) + "\n") ``` **Skip condition:** `.env` already exists with all required values. --- ## Step 4: Set up project structure (new projects only) If this is a new project (no `scripts/` directory): ``` mkdir -p solutions plugins scripts ``` Ensure `scripts/auth.py` and `scripts/enable-mcp-client.py` exist -- see [`references/helper-scripts.md`](references/helper-scripts.md). Copy `templates/CLAUDE.md` to the repo root if it doesn't exist. Replace placeholders (`{{DATAVERSE_URL}}`, `{{SOLUTION_NAME}}`, `{{PUBLISHER_PREFIX}}`) with values from `.env`. --- ## Step 5: Verify the connection ``` dataverse auth who pac org who python scripts/auth.py --check ``` `--check` makes a **real data-plane call** (not just a token) — the only proof the org is actually reachable; a token can be minted while the org domain is blocked. All must resolve the same user/environment, proving the DV CLI cache, the PAC profile (Step 2b), and Python's reuse of the shared cache are wired. **If any fail:** - `dataverse auth who` fails → re-run Step 2. - `pac org who` fails → re-run Step 2b. - `python scripts/auth.py --check` prints a device-code URL → browser/WAM cache has no Python-reusable token. **Auto-fix:** re-run `dataverse auth create --environment <url> --deviceCode`, then retry. If it *still* prompts, check `pip show msal msal-extensions`. **Headless hosts** (ChatGPT / Codex cloud / CI): `dataverse auth create` can't persist here — don't loop (see [headless-hosts.md](references/headless-hosts.md)). - `python scripts/auth.py --check` prints `NOT REACHABLE` with a connection/timeout error → the org domain is blocked by network egress, not auth. Do NOT report success or a count — see [headless-hosts.md](references/headless-hosts.md) remediation. - Other Python error → check SDK install and `.env`. Before metadata work, also confirm the account has the `prvCreateEntity` customization privilege — see [tools-setup.md](references/tools-setup.md#privilege-preflight). --- ## Step 6: Configure MCP server **Skip this step** only when the current host points to the selected environment: - Gemini: `gemini mcp list` resolves bundled server `dataverse` to the selected URL - Antigravity: `agy mcp list` contains the selected environment - Other hosts: their MCP list or config contains a Dataverse server for the selected URL If MCP is not configured, follow [mcp-configuration.md](references/mcp-configuration.md): 1. Detect which tool the user is running (Copilot, Claude, Cursor, Codex, Gemini, or Antigravity) from context 2. Set `MCP_CLIENT_ID` based on tool choice 3. Get environment URL from `.env` 4. Default to GA endpoint (`/api/mcp`) 5. Register the MCP server per host (see the per-host blocks below) 6. Handle Dataverse admin consent and allowlist — prefer `dataverse mcp allow <MCP_CLIENT_ID>` over the portal (one-time per tenant/environment) 7. If `ERP_URL` exists, separately allowlist and validate ERP **Plugin attribution for MCP:** This plugin uses the **stdio proxy** transport (`npx @microsoft/dataverse mcp <url>`). When registering it, include `DATAVERSE_OPERATION_CONTEXT` in the env block so the CLI appends it to its User-Agent on requests to `/api/mcp`. Build the value from `.env`: ```
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub