mcp-dataverse 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/.env.example +15 -0
  2. package/CAPABILITIES.md +992 -0
  3. package/LICENSE +21 -0
  4. package/README.md +277 -0
  5. package/config.example.json +11 -0
  6. package/dist/auth/auth-provider.factory.d.ts +4 -0
  7. package/dist/auth/auth-provider.factory.d.ts.map +1 -0
  8. package/dist/auth/auth-provider.factory.js +15 -0
  9. package/dist/auth/auth-provider.factory.js.map +1 -0
  10. package/dist/auth/auth-provider.interface.d.ts +21 -0
  11. package/dist/auth/auth-provider.interface.d.ts.map +1 -0
  12. package/dist/auth/auth-provider.interface.js +2 -0
  13. package/dist/auth/auth-provider.interface.js.map +1 -0
  14. package/dist/auth/msal-auth-provider.d.ts +14 -0
  15. package/dist/auth/msal-auth-provider.d.ts.map +1 -0
  16. package/dist/auth/msal-auth-provider.js +62 -0
  17. package/dist/auth/msal-auth-provider.js.map +1 -0
  18. package/dist/auth/pac-auth-provider.d.ts +19 -0
  19. package/dist/auth/pac-auth-provider.d.ts.map +1 -0
  20. package/dist/auth/pac-auth-provider.js +153 -0
  21. package/dist/auth/pac-auth-provider.js.map +1 -0
  22. package/dist/config/config.loader.d.ts +3 -0
  23. package/dist/config/config.loader.d.ts.map +1 -0
  24. package/dist/config/config.loader.js +52 -0
  25. package/dist/config/config.loader.js.map +1 -0
  26. package/dist/config/config.schema.d.ts +34 -0
  27. package/dist/config/config.schema.d.ts.map +1 -0
  28. package/dist/config/config.schema.js +25 -0
  29. package/dist/config/config.schema.js.map +1 -0
  30. package/dist/dataverse/dataverse-client-advanced.d.ts +47 -0
  31. package/dist/dataverse/dataverse-client-advanced.d.ts.map +1 -0
  32. package/dist/dataverse/dataverse-client-advanced.js +147 -0
  33. package/dist/dataverse/dataverse-client-advanced.js.map +1 -0
  34. package/dist/dataverse/dataverse-client.d.ts +49 -0
  35. package/dist/dataverse/dataverse-client.d.ts.map +1 -0
  36. package/dist/dataverse/dataverse-client.js +313 -0
  37. package/dist/dataverse/dataverse-client.js.map +1 -0
  38. package/dist/dataverse/dataverse-client.metadata.d.ts +40 -0
  39. package/dist/dataverse/dataverse-client.metadata.d.ts.map +1 -0
  40. package/dist/dataverse/dataverse-client.metadata.js +121 -0
  41. package/dist/dataverse/dataverse-client.metadata.js.map +1 -0
  42. package/dist/dataverse/dataverse-client.utils.d.ts +14 -0
  43. package/dist/dataverse/dataverse-client.utils.d.ts.map +1 -0
  44. package/dist/dataverse/dataverse-client.utils.js +65 -0
  45. package/dist/dataverse/dataverse-client.utils.js.map +1 -0
  46. package/dist/dataverse/http-client.d.ts +36 -0
  47. package/dist/dataverse/http-client.d.ts.map +1 -0
  48. package/dist/dataverse/http-client.js +103 -0
  49. package/dist/dataverse/http-client.js.map +1 -0
  50. package/dist/dataverse/types.d.ts +68 -0
  51. package/dist/dataverse/types.d.ts.map +1 -0
  52. package/dist/dataverse/types.js +2 -0
  53. package/dist/dataverse/types.js.map +1 -0
  54. package/dist/server.d.ts +3 -0
  55. package/dist/server.d.ts.map +1 -0
  56. package/dist/server.js +165 -0
  57. package/dist/server.js.map +1 -0
  58. package/dist/setup-auth.d.ts +2 -0
  59. package/dist/setup-auth.d.ts.map +1 -0
  60. package/dist/setup-auth.js +29 -0
  61. package/dist/setup-auth.js.map +1 -0
  62. package/dist/tools/actions.tools.d.ts +170 -0
  63. package/dist/tools/actions.tools.d.ts.map +1 -0
  64. package/dist/tools/actions.tools.js +179 -0
  65. package/dist/tools/actions.tools.js.map +1 -0
  66. package/dist/tools/annotations.tools.d.ts +82 -0
  67. package/dist/tools/annotations.tools.d.ts.map +1 -0
  68. package/dist/tools/annotations.tools.js +180 -0
  69. package/dist/tools/annotations.tools.js.map +1 -0
  70. package/dist/tools/audit.tools.d.ts +45 -0
  71. package/dist/tools/audit.tools.d.ts.map +1 -0
  72. package/dist/tools/audit.tools.js +163 -0
  73. package/dist/tools/audit.tools.js.map +1 -0
  74. package/dist/tools/auth.tools.d.ts +17 -0
  75. package/dist/tools/auth.tools.d.ts.map +1 -0
  76. package/dist/tools/auth.tools.js +30 -0
  77. package/dist/tools/auth.tools.js.map +1 -0
  78. package/dist/tools/batch.tools.d.ts +45 -0
  79. package/dist/tools/batch.tools.d.ts.map +1 -0
  80. package/dist/tools/batch.tools.js +71 -0
  81. package/dist/tools/batch.tools.js.map +1 -0
  82. package/dist/tools/crud.tools.d.ts +206 -0
  83. package/dist/tools/crud.tools.d.ts.map +1 -0
  84. package/dist/tools/crud.tools.js +213 -0
  85. package/dist/tools/crud.tools.js.map +1 -0
  86. package/dist/tools/customization.tools.d.ts +75 -0
  87. package/dist/tools/customization.tools.d.ts.map +1 -0
  88. package/dist/tools/customization.tools.js +187 -0
  89. package/dist/tools/customization.tools.js.map +1 -0
  90. package/dist/tools/environment.tools.d.ts +40 -0
  91. package/dist/tools/environment.tools.d.ts.map +1 -0
  92. package/dist/tools/environment.tools.js +145 -0
  93. package/dist/tools/environment.tools.js.map +1 -0
  94. package/dist/tools/file.tools.d.ts +61 -0
  95. package/dist/tools/file.tools.d.ts.map +1 -0
  96. package/dist/tools/file.tools.js +142 -0
  97. package/dist/tools/file.tools.js.map +1 -0
  98. package/dist/tools/impersonate.tools.d.ts +37 -0
  99. package/dist/tools/impersonate.tools.d.ts.map +1 -0
  100. package/dist/tools/impersonate.tools.js +85 -0
  101. package/dist/tools/impersonate.tools.js.map +1 -0
  102. package/dist/tools/metadata.tools.d.ts +156 -0
  103. package/dist/tools/metadata.tools.d.ts.map +1 -0
  104. package/dist/tools/metadata.tools.js +200 -0
  105. package/dist/tools/metadata.tools.js.map +1 -0
  106. package/dist/tools/org.tools.d.ts +26 -0
  107. package/dist/tools/org.tools.d.ts.map +1 -0
  108. package/dist/tools/org.tools.js +57 -0
  109. package/dist/tools/org.tools.js.map +1 -0
  110. package/dist/tools/quality.tools.d.ts +30 -0
  111. package/dist/tools/quality.tools.d.ts.map +1 -0
  112. package/dist/tools/quality.tools.js +69 -0
  113. package/dist/tools/quality.tools.js.map +1 -0
  114. package/dist/tools/query.tools.d.ts +120 -0
  115. package/dist/tools/query.tools.d.ts.map +1 -0
  116. package/dist/tools/query.tools.js +182 -0
  117. package/dist/tools/query.tools.js.map +1 -0
  118. package/dist/tools/relations.tools.d.ts +65 -0
  119. package/dist/tools/relations.tools.d.ts.map +1 -0
  120. package/dist/tools/relations.tools.js +64 -0
  121. package/dist/tools/relations.tools.js.map +1 -0
  122. package/dist/tools/search.tools.d.ts +68 -0
  123. package/dist/tools/search.tools.d.ts.map +1 -0
  124. package/dist/tools/search.tools.js +134 -0
  125. package/dist/tools/search.tools.js.map +1 -0
  126. package/dist/tools/solution.tools.d.ts +95 -0
  127. package/dist/tools/solution.tools.d.ts.map +1 -0
  128. package/dist/tools/solution.tools.js +130 -0
  129. package/dist/tools/solution.tools.js.map +1 -0
  130. package/dist/tools/teams.tools.d.ts +27 -0
  131. package/dist/tools/teams.tools.d.ts.map +1 -0
  132. package/dist/tools/teams.tools.js +67 -0
  133. package/dist/tools/teams.tools.js.map +1 -0
  134. package/dist/tools/trace.tools.d.ts +63 -0
  135. package/dist/tools/trace.tools.d.ts.map +1 -0
  136. package/dist/tools/trace.tools.js +218 -0
  137. package/dist/tools/trace.tools.js.map +1 -0
  138. package/dist/tools/tracking.tools.d.ts +35 -0
  139. package/dist/tools/tracking.tools.d.ts.map +1 -0
  140. package/dist/tools/tracking.tools.js +40 -0
  141. package/dist/tools/tracking.tools.js.map +1 -0
  142. package/dist/tools/users.tools.d.ts +57 -0
  143. package/dist/tools/users.tools.d.ts.map +1 -0
  144. package/dist/tools/users.tools.js +146 -0
  145. package/dist/tools/users.tools.js.map +1 -0
  146. package/dist/tools/views.tools.d.ts +30 -0
  147. package/dist/tools/views.tools.d.ts.map +1 -0
  148. package/dist/tools/views.tools.js +84 -0
  149. package/dist/tools/views.tools.js.map +1 -0
  150. package/package.json +81 -0
  151. package/server.json +30 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MCP Dataverse Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,277 @@
1
+ # MCP Dataverse Server
2
+
3
+ ![MCP Dataverse Logo](assets/logo.webp)
4
+
5
+ ![Node 20+](https://img.shields.io/badge/Node.js-20%2B-green) ![TypeScript](https://img.shields.io/badge/TypeScript-5.4-blue) ![MCP](https://img.shields.io/badge/MCP-1.0-purple) ![npm](https://img.shields.io/npm/v/mcp-dataverse) ![License: MIT](https://img.shields.io/badge/License-MIT-yellow)
6
+
7
+ MCP server that exposes the Microsoft Dataverse Web API as **39 AI-callable tools** — enabling GitHub Copilot, Claude, and other MCP clients to query, create, and manage Dataverse records without hallucinating schema.
8
+
9
+ ## Install
10
+
11
+ ### One-click (VS Code)
12
+
13
+ [Install in VS Code](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522mcp-dataverse%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522mcp-dataverse%2522%255D%257D)
14
+
15
+ ### Manual (npx)
16
+
17
+ Add to your `.vscode/mcp.json` (or user settings):
18
+
19
+ ```json
20
+ {
21
+ "servers": {
22
+ "dataverse": {
23
+ "type": "stdio",
24
+ "command": "npx",
25
+ "args": ["-y", "mcp-dataverse"]
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## Prerequisites
32
+
33
+ - Node.js 20+
34
+ - PAC CLI installed & authenticated → [aka.ms/PowerAppsCLI](https://aka.ms/PowerAppsCLI)
35
+ - VS Code + GitHub Copilot (Agent mode)
36
+
37
+ ## Quick Start (< 5 min)
38
+
39
+ ### 1. Clone & install
40
+
41
+ ```bash
42
+ git clone <repo-url> mcp-dataverse && cd mcp-dataverse
43
+ npm install
44
+ ```
45
+
46
+ ### 2. Configure
47
+
48
+ ```bash
49
+ cp config.example.json config.json
50
+ ```
51
+
52
+ Edit `config.json`:
53
+
54
+ | Field | Description |
55
+ |-------|-------------|
56
+ | `environmentUrl` | Your org URL, e.g. `https://yourorg.crm.dynamics.com` |
57
+ | `authMode` | `"pac"` (recommended) or `"msal"` |
58
+ | `pacProfileName` | PAC CLI profile name (default: `"default"`) |
59
+ | `requestTimeoutMs` | HTTP timeout in ms (default: `30000`) |
60
+ | `maxRetries` | Retry count on transient errors (default: `3`) |
61
+
62
+ ### 3. Authenticate
63
+
64
+ ```bash
65
+ npm run auth:setup
66
+ ```
67
+
68
+ Runs device code authentication. Follow the URL printed to the terminal — sign in with your Power Platform account. Token is cached in `.msal-cache.json` for silent reuse.
69
+
70
+ > Only required for `authMode: "pac"`. Skip if PAC CLI (`pac auth create`) is already authenticated.
71
+
72
+ ### 4. Build
73
+
74
+ ```bash
75
+ npm run build
76
+ ```
77
+
78
+ ### 5. Verify the connection
79
+
80
+ ```bash
81
+ npx tsx tests/live/test-whoami.ts
82
+ ```
83
+
84
+ Expected output:
85
+ ```
86
+ WhoAmI result: { UserId: 'xxxxxxxx-...', BusinessUnitId: 'xxxxxxxx-...', OrganizationId: 'xxxxxxxx-...' }
87
+ ```
88
+
89
+ ### 6. Configure VS Code
90
+
91
+ `.vscode/mcp.json` is already present in this repo. If you need to add it manually:
92
+
93
+ ```json
94
+ {
95
+ "servers": {
96
+ "dataverse": {
97
+ "type": "stdio",
98
+ "command": "node",
99
+ "args": ["${workspaceFolder}/dist/server.js"],
100
+ "env": {}
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ 1. Restart VS Code
107
+ 2. Open GitHub Copilot chat → switch to **Agent mode** (⚡)
108
+ 3. Test: _"List the Dataverse tables in my environment"_
109
+
110
+ ---
111
+
112
+ ## Tools (48)
113
+
114
+ | Tool | Category | Description |
115
+ |------|----------|-------------|
116
+ | `dataverse_whoami` | Auth | Verify connection; returns UserId, BusinessUnitId, OrgId |
117
+ | `dataverse_list_tables` | Metadata | List all tables (`customOnly` filter available) |
118
+ | `dataverse_get_table_metadata` | Metadata | Full schema: columns, types, logical names |
119
+ | `dataverse_get_relationships` | Metadata | All 1:N, N:1, N:N relationships for a table; filter by `relationshipType` |
120
+ | `dataverse_list_global_option_sets` | Metadata | All global option sets in the environment |
121
+ | `dataverse_get_option_set` | Metadata | Options and values for a specific option set |
122
+ | `dataverse_get_entity_key` | Metadata | Alternate key definitions for a table (fields, index status, customizable flag) |
123
+ | `dataverse_query` | Query | OData query with `$select`, `$filter`, `$orderby`, `$expand`, `$count` |
124
+ | `dataverse_execute_fetchxml` | Query | Raw FetchXML for aggregations and complex joins |
125
+ | `dataverse_retrieve_multiple_with_paging` | Query | Paginated query following `@odata.nextLink`, with configurable `maxTotal` cap |
126
+ | `dataverse_get` | CRUD | Retrieve a single record by GUID |
127
+ | `dataverse_create` | CRUD | Create a record; returns the new GUID |
128
+ | `dataverse_update` | CRUD | Patch a record — only specified fields are changed |
129
+ | `dataverse_delete` | CRUD | Delete a record (requires explicit confirm) |
130
+ | `dataverse_upsert` | CRUD | Create-or-update via alternate key |
131
+ | `dataverse_associate` | Relations | Associate two records via a named relationship |
132
+ | `dataverse_disassociate` | Relations | Remove an association between two records |
133
+ | `dataverse_execute_action` | Actions | Execute a global (unbound) Dataverse action |
134
+ | `dataverse_execute_function` | Actions | Execute a global read-only function (e.g. `WhoAmI`) |
135
+ | `dataverse_execute_bound_action` | Actions | Execute an action bound to a specific record |
136
+ | `dataverse_execute_bound_function` | Actions | Execute an OData bound function on a specific record |
137
+ | `dataverse_retrieve_dependencies_for_delete` | Actions | Check what components block deletion of a Dataverse component |
138
+ | `dataverse_list_dependencies` | Actions | List component dependencies before modifying or deleting |
139
+ | `dataverse_batch_execute` | Batch | Up to 1000 operations in a single HTTP batch request; optional atomic changeset |
140
+ | `dataverse_change_detection` | Tracking | Delta tracking using change tokens to detect record changes since last sync |
141
+ | `dataverse_solution_components` | Solution | List all components in a named solution; filter by component type code |
142
+ | `dataverse_publish_customizations` | Solution | Publish pending customizations (all or targeted entities/web resources/option sets) |
143
+ | `dataverse_impersonate` | Impersonation | Execute any tool on behalf of another Dataverse user via `MSCRMCallerId` |
144
+ | `dataverse_list_custom_actions` | Customization | Lists custom actions (custom API / SDK messages) in the environment |
145
+ | `dataverse_list_plugin_steps` | Customization | Lists plugin step registrations with stage, mode, entity, and state |
146
+ | `dataverse_get_environment_variable` | Environment | Retrieve an environment variable definition and current value |
147
+ | `dataverse_set_environment_variable` | Environment | Set or update an environment variable value |
148
+ | `dataverse_get_plugin_trace_logs` | Trace | Retrieve plugin execution trace logs for debugging |
149
+ | `dataverse_get_workflow_trace_logs` | Trace | Retrieve async workflow/system job execution logs |
150
+ | `dataverse_search` | Search | Full-text Relevance Search across all configured tables |
151
+ | `dataverse_get_audit_log` | Audit | Retrieve audit trail for a record showing change history |
152
+ | `dataverse_detect_duplicates` | Quality | Check for potential duplicates before creating a record |
153
+ | `dataverse_get_annotations` | Annotations | Retrieve notes and file attachments linked to a record |
154
+ | `dataverse_list_users` | Users | Search system users by name or email with BU filtering |
155
+ | `dataverse_get_user_roles` | Users | Security roles assigned to a system user |
156
+ | `dataverse_create_annotation` | Annotations | Create a note or file attachment linked to a record |
157
+ | `dataverse_get_attribute_option_set` | Metadata | Local/entity-specific option set values (statecode, statuscode, picklist) |
158
+ | `dataverse_list_solutions` | Solution | List all solutions in the environment |
159
+ | `dataverse_set_workflow_state` | Customization | Enable or disable a workflow or process |
160
+ | `dataverse_list_views` | Views | List system and personal saved views for a table |
161
+ | `dataverse_upload_file_column` | Files | Upload binary content to a file/image column on a record |
162
+ | `dataverse_download_file_column` | Files | Download binary content from a file/image column on a record |
163
+ | `dataverse_list_business_units` | Org | List business units in the environment (org hierarchy) |
164
+
165
+ ---
166
+
167
+ ## Advanced Configuration (MSAL)
168
+
169
+ For service-principal auth (CI/CD, unattended), set `authMode: "msal"` in `config.json`:
170
+
171
+ ```json
172
+ {
173
+ "environmentUrl": "https://yourorg.crm.dynamics.com",
174
+ "authMode": "msal",
175
+ "tenantId": "<azure-ad-tenant-id>",
176
+ "clientId": "<app-registration-client-id>",
177
+ "clientSecret": "<client-secret>"
178
+ }
179
+ ```
180
+
181
+ > The app registration must have the **Dynamics CRM → user_impersonation** API permission and the corresponding Dataverse security role.
182
+
183
+ ---
184
+
185
+ ## Scripts
186
+
187
+ | Command | Description |
188
+ |---------|-------------|
189
+ | `npm run build` | Compile TypeScript → `dist/` |
190
+ | `npm run dev` | Watch mode — no build step needed |
191
+ | `npm start` | Start the compiled server |
192
+ | `npm run auth:setup` | One-time device code authentication |
193
+ | `npm run typecheck` | Type-check without emitting output |
194
+ | `npm run lint` | ESLint on `src/` |
195
+ | `npm run test:unit` | Unit tests only |
196
+ | `npm run test:integration` | Integration tests |
197
+ | `npm test` | All tests |
198
+
199
+ ---
200
+
201
+ ## Architecture
202
+
203
+ TypeScript MCP server over **stdio** transport. An `AuthProvider` (PAC CLI or MSAL) injects Bearer tokens into a native-`fetch`-based `HttpClient` wrapped by `DataverseClient`. Each tool module registers handlers with the MCP `Server` instance.
204
+
205
+ ```
206
+ GitHub Copilot → stdio → MCP Server → Tool Router → DataverseClient → Dataverse Web API v9.2
207
+ └── AuthProvider (PAC CLI | MSAL)
208
+ ```
209
+
210
+ ---
211
+
212
+ ## Security
213
+
214
+ - **Never commit `config.json`** or `.msal-cache.json` — both are in `.gitignore`
215
+ - Tokens are never logged; only diagnostic messages are written to stderr
216
+ - PAC CLI tokens are scoped to the authenticated user — no privilege escalation
217
+ - Service principal (`msal`) should be assigned the least-privilege Dataverse security role
218
+
219
+ ---
220
+
221
+ ## Docker
222
+
223
+ The server ships as a single-process stdio MCP server — no HTTP port is exposed.
224
+ **MSAL client credentials** is the recommended auth mode for containers; `PAC_CLI` mode requires an interactive device-code flow and is not suitable for container environments.
225
+
226
+ ### Build the image
227
+
228
+ ```bash
229
+ docker build -t mcp-dataverse .
230
+ ```
231
+
232
+ ### Run with MSAL client credentials
233
+
234
+ ```bash
235
+ docker run --rm -i \
236
+ -e ENVIRONMENT_URL=https://yourorg.crm.dynamics.com \
237
+ -e CLIENT_ID=your-client-id \
238
+ -e CLIENT_SECRET=your-client-secret \
239
+ -e TENANT_ID=your-tenant-id \
240
+ mcp-dataverse
241
+ ```
242
+
243
+ > The app registration must have the **Dynamics CRM → user_impersonation** API permission and a Dataverse security role assigned.
244
+
245
+ ### Claude Desktop config (Docker)
246
+
247
+ Add the following to your Claude Desktop `claude_desktop_config.json`:
248
+
249
+ ```json
250
+ {
251
+ "mcpServers": {
252
+ "dataverse": {
253
+ "command": "docker",
254
+ "args": [
255
+ "run", "--rm", "-i",
256
+ "-e", "ENVIRONMENT_URL=https://yourorg.crm.dynamics.com",
257
+ "-e", "CLIENT_ID=your-client-id",
258
+ "-e", "CLIENT_SECRET=your-client-secret",
259
+ "-e", "TENANT_ID=your-tenant-id",
260
+ "mcp-dataverse"
261
+ ]
262
+ }
263
+ }
264
+ }
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Troubleshooting
270
+
271
+ | Symptom | Fix |
272
+ |---------|-----|
273
+ | `No MSAL accounts found` | Run `npm run auth:setup` to re-authenticate |
274
+ | `"https://" is required` | Check `environmentUrl` in `config.json` — must start with `https://` |
275
+ | `pac: command not found` | Install PAC CLI and run `pac auth create --environment <url>` |
276
+ | Server not appearing in Copilot Agent mode | Restart VS Code; check **Output → MCP** panel for errors |
277
+
@@ -0,0 +1,11 @@
1
+ {
2
+ "environmentUrl": "https://yourorg.crm.dynamics.com",
3
+ "authMode": "pac",
4
+ "pacProfileName": "default",
5
+ "tenantId": "",
6
+ "clientId": "",
7
+ "clientSecret": "",
8
+ "redirectUri": "http://localhost:3000/auth/callback",
9
+ "requestTimeoutMs": 30000,
10
+ "maxRetries": 3
11
+ }
@@ -0,0 +1,4 @@
1
+ import type { AuthProvider } from './auth-provider.interface.js';
2
+ import type { Config } from '../config/config.schema.js';
3
+ export declare function createAuthProvider(config: Config): AuthProvider;
4
+ //# sourceMappingURL=auth-provider.factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-provider.factory.d.ts","sourceRoot":"","sources":["../../src/auth/auth-provider.factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAGjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEzD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAW/D"}
@@ -0,0 +1,15 @@
1
+ import { PacAuthProvider } from './pac-auth-provider.js';
2
+ import { MsalAuthProvider } from './msal-auth-provider.js';
3
+ export function createAuthProvider(config) {
4
+ switch (config.authMode) {
5
+ case 'pac':
6
+ return new PacAuthProvider(config.environmentUrl);
7
+ case 'msal':
8
+ return new MsalAuthProvider(config);
9
+ default: {
10
+ const _exhaustive = config.authMode;
11
+ throw new Error(`Unknown auth mode: ${_exhaustive}`);
12
+ }
13
+ }
14
+ }
15
+ //# sourceMappingURL=auth-provider.factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-provider.factory.js","sourceRoot":"","sources":["../../src/auth/auth-provider.factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAG3D,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,KAAK;YACR,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACpD,KAAK,MAAM;YACT,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACtC,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,WAAW,GAAU,MAAM,CAAC,QAAQ,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ export interface AuthProvider {
2
+ /**
3
+ * Returns a valid Bearer token for the Dataverse environment.
4
+ * Implementations must handle token refresh silently.
5
+ */
6
+ getToken(): Promise<string>;
7
+ /**
8
+ * Invalidates any cached token, forcing a fresh acquisition on the next getToken() call.
9
+ * Must be called before retrying a request that received a 401 response.
10
+ */
11
+ invalidateToken(): void;
12
+ /**
13
+ * Returns true if the current auth session is valid.
14
+ */
15
+ isAuthenticated(): Promise<boolean>;
16
+ /**
17
+ * The Dataverse environment URL this provider authenticates against.
18
+ */
19
+ readonly environmentUrl: string;
20
+ }
21
+ //# sourceMappingURL=auth-provider.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-provider.interface.d.ts","sourceRoot":"","sources":["../../src/auth/auth-provider.interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE5B;;;OAGG;IACH,eAAe,IAAI,IAAI,CAAC;IAExB;;OAEG;IACH,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=auth-provider.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-provider.interface.js","sourceRoot":"","sources":["../../src/auth/auth-provider.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import type { AuthProvider } from './auth-provider.interface.js';
2
+ import type { Config } from '../config/config.schema.js';
3
+ export declare class MsalAuthProvider implements AuthProvider {
4
+ readonly environmentUrl: string;
5
+ private readonly msalApp;
6
+ private readonly scope;
7
+ private cachedToken;
8
+ private tokenExpiresAt;
9
+ constructor(config: Config);
10
+ getToken(): Promise<string>;
11
+ invalidateToken(): void;
12
+ isAuthenticated(): Promise<boolean>;
13
+ }
14
+ //# sourceMappingURL=msal-auth-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msal-auth-provider.d.ts","sourceRoot":"","sources":["../../src/auth/msal-auth-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEzD,qBAAa,gBAAiB,YAAW,YAAY;IACnD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAqB;gBAE/B,MAAM,EAAE,MAAM;IA0BpB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAuBjC,eAAe,IAAI,IAAI;IAKjB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;CAQ1C"}
@@ -0,0 +1,62 @@
1
+ import { ConfidentialClientApplication } from '@azure/msal-node';
2
+ export class MsalAuthProvider {
3
+ environmentUrl;
4
+ msalApp;
5
+ scope;
6
+ cachedToken = null;
7
+ tokenExpiresAt = null;
8
+ constructor(config) {
9
+ this.environmentUrl = config.environmentUrl;
10
+ if (!config.tenantId) {
11
+ throw new Error('MsalAuthProvider requires config.tenantId for client_credentials flow');
12
+ }
13
+ if (!config.clientId) {
14
+ throw new Error('MsalAuthProvider requires config.clientId for client_credentials flow');
15
+ }
16
+ if (!config.clientSecret) {
17
+ throw new Error('MsalAuthProvider requires config.clientSecret for client_credentials flow');
18
+ }
19
+ this.msalApp = new ConfidentialClientApplication({
20
+ auth: {
21
+ clientId: config.clientId,
22
+ clientSecret: config.clientSecret,
23
+ authority: `https://login.microsoftonline.com/${config.tenantId}`,
24
+ },
25
+ });
26
+ // Scope for Dataverse client_credentials: <environmentUrl>/.default
27
+ const baseUrl = config.environmentUrl.replace(/\/$/, '');
28
+ this.scope = `${baseUrl}/.default`;
29
+ }
30
+ async getToken() {
31
+ // Return cached token if still valid (60-second buffer before expiry)
32
+ if (this.cachedToken !== null && this.tokenExpiresAt !== null && new Date() < this.tokenExpiresAt) {
33
+ return this.cachedToken;
34
+ }
35
+ const result = await this.msalApp.acquireTokenByClientCredential({
36
+ scopes: [this.scope],
37
+ });
38
+ if (result === null || !result.accessToken) {
39
+ throw new Error('MSAL: acquireTokenByClientCredential returned no access token');
40
+ }
41
+ this.cachedToken = result.accessToken;
42
+ // Subtract 60 seconds from expiry to avoid using a token that is about to expire
43
+ this.tokenExpiresAt = result.expiresOn
44
+ ? new Date(result.expiresOn.getTime() - 60_000)
45
+ : new Date(Date.now() + 3_540_000); // fallback: 59 minutes
46
+ return this.cachedToken;
47
+ }
48
+ invalidateToken() {
49
+ this.cachedToken = null;
50
+ this.tokenExpiresAt = null;
51
+ }
52
+ async isAuthenticated() {
53
+ try {
54
+ await this.getToken();
55
+ return true;
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }
61
+ }
62
+ //# sourceMappingURL=msal-auth-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msal-auth-provider.js","sourceRoot":"","sources":["../../src/auth/msal-auth-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAIjE,MAAM,OAAO,gBAAgB;IAClB,cAAc,CAAS;IACf,OAAO,CAAgC;IACvC,KAAK,CAAS;IACvB,WAAW,GAAkB,IAAI,CAAC;IAClC,cAAc,GAAgB,IAAI,CAAC;IAE3C,YAAY,MAAc;QACxB,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;QAE5C,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC3F,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC3F,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;QAC/F,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,6BAA6B,CAAC;YAC/C,IAAI,EAAE;gBACJ,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,SAAS,EAAE,qCAAqC,MAAM,CAAC,QAAQ,EAAE;aAClE;SACF,CAAC,CAAC;QAEH,oEAAoE;QACpE,MAAM,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK,GAAG,GAAG,OAAO,WAAW,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,sEAAsE;QACtE,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;YAClG,OAAO,IAAI,CAAC,WAAW,CAAC;QAC1B,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,8BAA8B,CAAC;YAC/D,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;SACrB,CAAC,CAAC;QAEH,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;QACnF,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACtC,iFAAiF;QACjF,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,SAAS;YACpC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC;YAC/C,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,uBAAuB;QAE7D,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,eAAe;QACb,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import type { AuthProvider } from './auth-provider.interface.js';
2
+ export declare class PacAuthProvider implements AuthProvider {
3
+ readonly environmentUrl: string;
4
+ private readonly pca;
5
+ private cachedToken;
6
+ private tokenExpiresAt;
7
+ constructor(environmentUrl: string);
8
+ getToken(): Promise<string>;
9
+ invalidateToken(): void;
10
+ isAuthenticated(): Promise<boolean>;
11
+ /**
12
+ * Interactive device code flow — call once via `npm run auth:setup`.
13
+ * Writes to stderr so it doesn't disturb the stdio MCP transport.
14
+ */
15
+ setupViaDeviceCode(): Promise<void>;
16
+ private refreshToken;
17
+ private cacheResult;
18
+ }
19
+ //# sourceMappingURL=pac-auth-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pac-auth-provider.d.ts","sourceRoot":"","sources":["../../src/auth/pac-auth-provider.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAwEjE,qBAAa,eAAgB,YAAW,YAAY;IAClD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA0B;IAC9C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAa;gBAEvB,cAAc,EAAE,MAAM;IAY5B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAQjC,eAAe,IAAI,IAAI;IAKjB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IASzC;;;OAGG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;YAY3B,YAAY;IAiC1B,OAAO,CAAC,WAAW;CAIpB"}
@@ -0,0 +1,153 @@
1
+ import { PublicClientApplication, } from '@azure/msal-node';
2
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto';
5
+ // Microsoft Power Platform CLI App ID — public client, no app registration needed
6
+ const PLATFORM_CLIENT_ID = '1950a258-227b-4e31-a9cf-717495945fc2';
7
+ const TOKEN_CACHE_FILE = join(process.cwd(), '.msal-cache.json');
8
+ /**
9
+ * Derives a machine+user-scoped encryption key.
10
+ * Not a substitute for OS-level credential storage (DPAPI/keytar), but prevents
11
+ * the cache file from being directly readable as plaintext by other processes.
12
+ */
13
+ function getDerivedKey() {
14
+ const seed = [
15
+ process.env['COMPUTERNAME'] ?? process.env['HOSTNAME'] ?? '',
16
+ process.env['USERNAME'] ?? process.env['USER'] ?? '',
17
+ 'mcp-dataverse-cache-v1',
18
+ ].join('.');
19
+ return createHash('sha256').update(seed).digest();
20
+ }
21
+ function encryptForDisk(plaintext) {
22
+ const key = getDerivedKey();
23
+ const iv = randomBytes(16);
24
+ const cipher = createCipheriv('aes-256-gcm', key, iv);
25
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()]);
26
+ return JSON.stringify({
27
+ v: 1,
28
+ iv: iv.toString('hex'),
29
+ tag: cipher.getAuthTag().toString('hex'),
30
+ d: encrypted.toString('hex'),
31
+ });
32
+ }
33
+ function decryptFromDisk(raw) {
34
+ const parsed = JSON.parse(raw);
35
+ if (parsed['v'] !== 1)
36
+ throw new Error('Unknown cache format version');
37
+ const iv = Buffer.from(parsed['iv'], 'hex');
38
+ const tag = Buffer.from(parsed['tag'], 'hex');
39
+ const encrypted = Buffer.from(parsed['d'], 'hex');
40
+ const decipher = createDecipheriv('aes-256-gcm', getDerivedKey(), iv);
41
+ decipher.setAuthTag(tag);
42
+ return decipher.update(encrypted).toString('utf-8') + decipher.final('utf-8');
43
+ }
44
+ function createCachePlugin() {
45
+ return {
46
+ beforeCacheAccess: async (cacheContext) => {
47
+ if (existsSync(TOKEN_CACHE_FILE)) {
48
+ try {
49
+ const raw = readFileSync(TOKEN_CACHE_FILE, 'utf-8');
50
+ // Support both encrypted (v1) and legacy plaintext caches
51
+ let serialized;
52
+ try {
53
+ serialized = decryptFromDisk(raw);
54
+ }
55
+ catch {
56
+ // Legacy plaintext — accept for migration, will be re-written encrypted
57
+ serialized = raw;
58
+ }
59
+ cacheContext.tokenCache.deserialize(serialized);
60
+ }
61
+ catch {
62
+ // Corrupt cache — ignore, user will need to re-authenticate
63
+ }
64
+ }
65
+ },
66
+ afterCacheAccess: async (cacheContext) => {
67
+ if (cacheContext.cacheHasChanged) {
68
+ writeFileSync(TOKEN_CACHE_FILE, encryptForDisk(cacheContext.tokenCache.serialize()), { encoding: 'utf-8', mode: 0o600 });
69
+ }
70
+ },
71
+ };
72
+ }
73
+ export class PacAuthProvider {
74
+ environmentUrl;
75
+ pca;
76
+ cachedToken = null;
77
+ tokenExpiresAt = 0;
78
+ constructor(environmentUrl) {
79
+ this.environmentUrl = environmentUrl.replace(/\/$/, '');
80
+ this.pca = new PublicClientApplication({
81
+ auth: {
82
+ clientId: PLATFORM_CLIENT_ID,
83
+ authority: 'https://login.microsoftonline.com/common',
84
+ },
85
+ cache: { cachePlugin: createCachePlugin() },
86
+ });
87
+ }
88
+ async getToken() {
89
+ const now = Date.now();
90
+ if (this.cachedToken !== null && this.tokenExpiresAt > now + 60_000) {
91
+ return this.cachedToken;
92
+ }
93
+ return this.refreshToken();
94
+ }
95
+ invalidateToken() {
96
+ this.cachedToken = null;
97
+ this.tokenExpiresAt = 0;
98
+ }
99
+ async isAuthenticated() {
100
+ try {
101
+ await this.getToken();
102
+ return true;
103
+ }
104
+ catch {
105
+ return false;
106
+ }
107
+ }
108
+ /**
109
+ * Interactive device code flow — call once via `npm run auth:setup`.
110
+ * Writes to stderr so it doesn't disturb the stdio MCP transport.
111
+ */
112
+ async setupViaDeviceCode() {
113
+ const result = await this.pca.acquireTokenByDeviceCode({
114
+ scopes: [`${this.environmentUrl}/.default`],
115
+ deviceCodeCallback: (response) => {
116
+ process.stderr.write(`\n${response.message}\n`);
117
+ },
118
+ });
119
+ if (result) {
120
+ this.cacheResult(result);
121
+ }
122
+ }
123
+ async refreshToken() {
124
+ const accounts = await this.pca.getAllAccounts();
125
+ if (accounts.length === 0) {
126
+ throw new Error('No authenticated account found.\n' +
127
+ 'Run once: npm run auth:setup\n' +
128
+ 'Then restart the server.');
129
+ }
130
+ try {
131
+ const result = await this.pca.acquireTokenSilent({
132
+ scopes: [`${this.environmentUrl}/.default`],
133
+ account: accounts[0],
134
+ });
135
+ if (!result?.accessToken) {
136
+ throw new Error('Silent token acquisition returned empty token');
137
+ }
138
+ this.cacheResult(result);
139
+ return result.accessToken;
140
+ }
141
+ catch {
142
+ this.cachedToken = null;
143
+ throw new Error('Token refresh failed. Re-authenticate:\n' +
144
+ 'npm run auth:setup\n' +
145
+ 'Then restart the server.');
146
+ }
147
+ }
148
+ cacheResult(result) {
149
+ this.cachedToken = result.accessToken;
150
+ this.tokenExpiresAt = result.expiresOn?.getTime() ?? (Date.now() + 55 * 60 * 1000);
151
+ }
152
+ }
153
+ //# sourceMappingURL=pac-auth-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pac-auth-provider.js","sourceRoot":"","sources":["../../src/auth/pac-auth-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type Config } from './config.schema.js';
2
+ export declare function loadConfig(): Config;
3
+ //# sourceMappingURL=config.loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.loader.d.ts","sourceRoot":"","sources":["../../src/config/config.loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAI/D,wBAAgB,UAAU,IAAI,MAAM,CAqDnC"}