|
| 1 | +--- |
| 2 | +name: Dataverse MCP setup |
| 3 | +description: Configure an MCP server for GitHub Copilot with your Dataverse environment. |
| 4 | +--- |
| 5 | + |
| 6 | +# Setup Dataverse MCP for GitHub Copilot |
| 7 | + |
| 8 | +This skill configures the Dataverse MCP server for GitHub Copilot with your organization's environment URL. Each organization is registered with a unique server name based on the org identifier (e.g., `DataverseMcporgbc9a965c`). If the user provided a URL it is: $ARGUMENTS. |
| 9 | + |
| 10 | +## Instructions |
| 11 | + |
| 12 | +### 0. Ask for MCP scope |
| 13 | + |
| 14 | +Ask the user whether they want to configure the MCP server globally or for this project only: |
| 15 | + |
| 16 | +> Would you like to configure the Dataverse MCP server: |
| 17 | +> 1. **Globally** (available in all projects) |
| 18 | +> 2. **Project-only** (available only in this project) |
| 19 | +
|
| 20 | +Based on their choice, set the `CONFIG_PATH` variable: |
| 21 | +- **Global**: `~/.copilot/mcp-config.json` (use the user's home directory) |
| 22 | +- **Project**: `.mcp/copilot/mcp.json` (relative to the current working directory) |
| 23 | + |
| 24 | +Store this path for use in steps 1 and 6. |
| 25 | + |
| 26 | +### 1. Check already-configured MCP servers |
| 27 | + |
| 28 | +Read the MCP configuration file at `CONFIG_PATH` (determined in step 0) to check for already-configured servers. |
| 29 | + |
| 30 | +The configuration file is a JSON file with the following structure: |
| 31 | + |
| 32 | +```json |
| 33 | +{ |
| 34 | + "mcpServers": { |
| 35 | + "ServerName1": { |
| 36 | + "type": "http", |
| 37 | + "url": "https://example.com/api/mcp" |
| 38 | + } |
| 39 | + } |
| 40 | +} |
| 41 | +``` |
| 42 | + |
| 43 | +Or it may use `"servers"` instead of `"mcpServers"` as the top-level key. |
| 44 | + |
| 45 | +Extract all `url` values from the configured servers and store them as `CONFIGURED_URLS`. For example: |
| 46 | + |
| 47 | +```json |
| 48 | +["https://orgfbb52bb7.crm.dynamics.com/api/mcp"] |
| 49 | +``` |
| 50 | + |
| 51 | +If the file doesn't exist or is empty, treat `CONFIGURED_URLS` as empty (`[]`). This step must never block the skill. |
| 52 | + |
| 53 | +### 2. Ask how to get the environment URL |
| 54 | + |
| 55 | +Ask the user: |
| 56 | + |
| 57 | +> How would you like to provide your Dataverse environment URL? |
| 58 | +> 1. **Auto-discover** — List available environments from your Azure account (requires Azure CLI) |
| 59 | +> 2. **Manual entry** — Enter the URL directly |
| 60 | +
|
| 61 | +Based on their choice: |
| 62 | +- If **Auto-discover**: Proceed to step 2a |
| 63 | +- If **Manual entry**: Skip to step 2b |
| 64 | + |
| 65 | +### 2a. Auto-discover environments |
| 66 | + |
| 67 | +**Check prerequisites:** |
| 68 | +- Verify Azure CLI (`az`) is installed (check with `which az` or `where az` on Windows) |
| 69 | +- If not installed, inform the user and fall back to step 2b |
| 70 | + |
| 71 | +**Make the API call:** |
| 72 | + |
| 73 | +1. Check if the user is logged into Azure CLI: |
| 74 | + ```bash |
| 75 | + az account show |
| 76 | + ``` |
| 77 | + If this fails, prompt the user to log in: |
| 78 | + ```bash |
| 79 | + az login |
| 80 | + ``` |
| 81 | + |
| 82 | +2. Get an access token for the Power Apps API: |
| 83 | + ```bash |
| 84 | + az account get-access-token --resource https://service.powerapps.com/ --query accessToken --output tsv |
| 85 | + ``` |
| 86 | + |
| 87 | +3. Call the Power Apps API to list environments: |
| 88 | + ``` |
| 89 | + GET https://api.powerapps.com/providers/Microsoft.PowerApps/environments?api-version=2016-11-01 |
| 90 | + Authorization: Bearer {token} |
| 91 | + Accept: application/json |
| 92 | + ``` |
| 93 | + |
| 94 | +4. Parse the JSON response and filter for environments where `properties.databaseType` is `"CommonDataService"`. |
| 95 | + |
| 96 | +5. For each matching environment, extract: |
| 97 | + - `properties.displayName` as `displayName` |
| 98 | + - `properties.linkedEnvironmentMetadata.instanceUrl` (remove trailing slash) as `instanceUrl` |
| 99 | + |
| 100 | +6. Create a list of environments in this format: |
| 101 | + ```json |
| 102 | + [ |
| 103 | + { "displayName": "My Org (default)", "instanceUrl": "https://orgfbb52bb7.crm.dynamics.com" }, |
| 104 | + { "displayName": "Another Env", "instanceUrl": "https://orgabc123.crm.dynamics.com" } |
| 105 | + ] |
| 106 | + ``` |
| 107 | + |
| 108 | +**If the API call succeeds**, proceed to step 3. |
| 109 | + |
| 110 | +**If the API call fails** (user not logged in, network error, no environments found, or any other error), tell the user what went wrong and fall back to step 2b. |
| 111 | + |
| 112 | +### 2b. Manual entry — ask for the URL |
| 113 | + |
| 114 | +Ask the user to provide their environment URL directly: |
| 115 | + |
| 116 | +> Please enter your Dataverse environment URL. |
| 117 | +> |
| 118 | +> Example: `https://myorg.crm10.dynamics.com` |
| 119 | +> |
| 120 | +> You can find this in the Power Platform Admin Center under Environments. |
| 121 | +
|
| 122 | +Then skip to step 4. |
| 123 | + |
| 124 | +### 3. Ask the user to select an environment |
| 125 | + |
| 126 | +Present the environments as a numbered list. For each environment, check whether any URL in `CONFIGURED_URLS` starts with that environment's `instanceUrl` — if so, append **(already configured)** to the line. |
| 127 | + |
| 128 | +> I found the following Dataverse environments on your account. Which one would you like to configure? |
| 129 | +> |
| 130 | +> 1. My Org (default) — `https://orgfbb52bb7.crm.dynamics.com` **(already configured)** |
| 131 | +> 2. Another Env — `https://orgabc123.crm.dynamics.com` |
| 132 | +> |
| 133 | +> Enter the number of your choice, or type "manual" to enter a URL yourself. |
| 134 | +
|
| 135 | +If the user selects an already-configured environment, confirm that they want to re-register it (e.g. to change the endpoint type) before proceeding. |
| 136 | + |
| 137 | +If the user types "manual", fall back to step 2b. |
| 138 | + |
| 139 | +### 4. Confirm the selected URL |
| 140 | + |
| 141 | +Take the `instanceUrl` from the chosen environment (or the manually entered URL) and strip any trailing slash. This is `USER_URL` for the remainder of the skill. |
| 142 | + |
| 143 | +### 5. Confirm if the user wants "Preview" or "Generally Available (GA)" endpoint |
| 144 | + |
| 145 | +Ask the user: |
| 146 | + |
| 147 | +> Which endpoint would you like to use? |
| 148 | +> 1. **Generally Available (GA)** — `/api/mcp` (recommended) |
| 149 | +> 2. **Preview** — `/api/mcp_preview` (latest features, may be unstable) |
| 150 | +
|
| 151 | +Based on their choice: |
| 152 | +- If **GA**: set `MCP_URL` to `{USER_URL}/api/mcp` |
| 153 | +- If **Preview**: set `MCP_URL` to `{USER_URL}/api/mcp_preview` |
| 154 | + |
| 155 | +### 6. Register the MCP server |
| 156 | + |
| 157 | +Update the MCP configuration file at `CONFIG_PATH` (determined in step 0) to add the new server. |
| 158 | + |
| 159 | +**Generate a unique server name** from the `USER_URL`: |
| 160 | +1. Extract the subdomain (organization identifier) from the URL |
| 161 | + - Example: `https://orgbc9a965c.crm10.dynamics.com` → `orgbc9a965c` |
| 162 | +2. Prepend `DataverseMcp` to create the server name |
| 163 | + - Example: `DataverseMcporgbc9a965c` |
| 164 | + |
| 165 | +This is the `SERVER_NAME`. |
| 166 | + |
| 167 | +**Update the configuration file:** |
| 168 | + |
| 169 | +1. If `CONFIG_PATH` is for a **project-scoped** configuration (`.mcp/copilot/mcp.json`), ensure the directory exists first: |
| 170 | + ```bash |
| 171 | + mkdir -p .mcp/copilot |
| 172 | + ``` |
| 173 | + |
| 174 | +2. Read the existing configuration file at `CONFIG_PATH`, or create a new empty config if it doesn't exist: |
| 175 | + ```json |
| 176 | + {} |
| 177 | + ``` |
| 178 | + |
| 179 | +3. Determine which top-level key to use: |
| 180 | + - If the config already has `"servers"`, use that |
| 181 | + - Otherwise, use `"mcpServers"` |
| 182 | + |
| 183 | +4. Add or update the server entry: |
| 184 | + ```json |
| 185 | + { |
| 186 | + "mcpServers": { |
| 187 | + "{SERVER_NAME}": { |
| 188 | + "type": "http", |
| 189 | + "url": "{MCP_URL}" |
| 190 | + } |
| 191 | + } |
| 192 | + } |
| 193 | + ``` |
| 194 | + |
| 195 | +5. Write the updated configuration back to `CONFIG_PATH` with proper JSON formatting (2-space indentation). |
| 196 | + |
| 197 | +**Important notes:** |
| 198 | +- Do NOT overwrite other entries in the configuration file |
| 199 | +- Preserve the existing structure and formatting |
| 200 | +- If `SERVER_NAME` already exists, update it with the new `MCP_URL` |
| 201 | + |
| 202 | +Proceed to step 7. |
| 203 | + |
| 204 | +### 7. Confirm success and instruct restart |
| 205 | + |
| 206 | +Tell the user: |
| 207 | + |
| 208 | +> ✅ Dataverse MCP server configured for GitHub Copilot at `{MCP_URL}`. |
| 209 | +> |
| 210 | +> Configuration saved to: `{CONFIG_PATH}` |
| 211 | +> |
| 212 | +> **IMPORTANT: You must restart your editor for the changes to take effect.** |
| 213 | +> |
| 214 | +> Restart your editor or reload the window, then you will be able to: |
| 215 | +> - List all tables in your Dataverse environment |
| 216 | +> - Query records from any table |
| 217 | +> - Create, update, or delete records |
| 218 | +> - Explore your schema and relationships |
| 219 | +
|
| 220 | +### 8. Troubleshooting |
| 221 | + |
| 222 | +If something goes wrong, help the user check: |
| 223 | + |
| 224 | +- The URL format is correct (`https://<org>.<region>.dynamics.com`) |
| 225 | +- They have access to the Dataverse environment |
| 226 | +- The environment URL matches what's shown in the Power Platform Admin Center |
| 227 | +- Their Environment Admin has enabled "Dataverse CLI MCP" in the Allowed Clients list |
| 228 | +- Their Environment has Dataverse MCP enabled, and if they're trying to use the preview endpoint that is enabled |
| 229 | +- For project-scoped configuration, ensure the `.mcp/copilot/mcp.json` file was created successfully |
| 230 | +- For global configuration, check permissions on the `~/.copilot/` directory |
0 commit comments