mcp-dataverse 0.3.0 → 0.3.2

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 (82) hide show
  1. package/CAPABILITIES.md +6 -4
  2. package/README.md +149 -244
  3. package/assets/logo.webp +0 -0
  4. package/dist/resources/resource-provider.d.ts +11 -0
  5. package/dist/resources/resource-provider.d.ts.map +1 -0
  6. package/dist/resources/resource-provider.js +79 -0
  7. package/dist/resources/resource-provider.js.map +1 -0
  8. package/dist/server.js +24 -5
  9. package/dist/server.js.map +1 -1
  10. package/dist/tools/actions.tools.js +6 -6
  11. package/dist/tools/actions.tools.js.map +1 -1
  12. package/dist/tools/annotations.tools.js +2 -2
  13. package/dist/tools/annotations.tools.js.map +1 -1
  14. package/dist/tools/audit.tools.d.ts.map +1 -1
  15. package/dist/tools/audit.tools.js +4 -1
  16. package/dist/tools/audit.tools.js.map +1 -1
  17. package/dist/tools/auth.tools.js +1 -1
  18. package/dist/tools/auth.tools.js.map +1 -1
  19. package/dist/tools/batch.tools.d.ts +2 -1
  20. package/dist/tools/batch.tools.d.ts.map +1 -1
  21. package/dist/tools/batch.tools.js +4 -2
  22. package/dist/tools/batch.tools.js.map +1 -1
  23. package/dist/tools/crud.tools.js +6 -6
  24. package/dist/tools/crud.tools.js.map +1 -1
  25. package/dist/tools/customization.tools.js +3 -3
  26. package/dist/tools/customization.tools.js.map +1 -1
  27. package/dist/tools/environment.tools.js +2 -2
  28. package/dist/tools/environment.tools.js.map +1 -1
  29. package/dist/tools/file.tools.js +2 -2
  30. package/dist/tools/file.tools.js.map +1 -1
  31. package/dist/tools/guardrails.d.ts +22 -0
  32. package/dist/tools/guardrails.d.ts.map +1 -0
  33. package/dist/tools/guardrails.js +55 -0
  34. package/dist/tools/guardrails.js.map +1 -0
  35. package/dist/tools/impersonate.tools.d.ts +2 -1
  36. package/dist/tools/impersonate.tools.d.ts.map +1 -1
  37. package/dist/tools/impersonate.tools.js +1 -1
  38. package/dist/tools/impersonate.tools.js.map +1 -1
  39. package/dist/tools/metadata.tools.js +7 -7
  40. package/dist/tools/metadata.tools.js.map +1 -1
  41. package/dist/tools/org.tools.js +1 -1
  42. package/dist/tools/org.tools.js.map +1 -1
  43. package/dist/tools/progress.d.ts +15 -0
  44. package/dist/tools/progress.d.ts.map +1 -0
  45. package/dist/tools/progress.js +29 -0
  46. package/dist/tools/progress.js.map +1 -0
  47. package/dist/tools/quality.tools.js +1 -1
  48. package/dist/tools/quality.tools.js.map +1 -1
  49. package/dist/tools/query.tools.d.ts +2 -1
  50. package/dist/tools/query.tools.d.ts.map +1 -1
  51. package/dist/tools/query.tools.js +6 -4
  52. package/dist/tools/query.tools.js.map +1 -1
  53. package/dist/tools/relations.tools.js +2 -2
  54. package/dist/tools/relations.tools.js.map +1 -1
  55. package/dist/tools/router.tools.d.ts +5 -0
  56. package/dist/tools/router.tools.d.ts.map +1 -0
  57. package/dist/tools/router.tools.js +247 -0
  58. package/dist/tools/router.tools.js.map +1 -0
  59. package/dist/tools/search.tools.js +1 -1
  60. package/dist/tools/search.tools.js.map +1 -1
  61. package/dist/tools/solution.tools.js +3 -3
  62. package/dist/tools/solution.tools.js.map +1 -1
  63. package/dist/tools/teams.tools.d.ts.map +1 -1
  64. package/dist/tools/teams.tools.js +4 -1
  65. package/dist/tools/teams.tools.js.map +1 -1
  66. package/dist/tools/tool-registry.d.ts +2 -1
  67. package/dist/tools/tool-registry.d.ts.map +1 -1
  68. package/dist/tools/tool-registry.js.map +1 -1
  69. package/dist/tools/trace.tools.js +2 -2
  70. package/dist/tools/trace.tools.js.map +1 -1
  71. package/dist/tools/tracking.tools.js +1 -1
  72. package/dist/tools/tracking.tools.js.map +1 -1
  73. package/dist/tools/users.tools.js +2 -2
  74. package/dist/tools/users.tools.js.map +1 -1
  75. package/dist/tools/views.tools.js +1 -1
  76. package/dist/tools/views.tools.js.map +1 -1
  77. package/dist/tools/workflow.tools.d.ts +53 -0
  78. package/dist/tools/workflow.tools.d.ts.map +1 -0
  79. package/dist/tools/workflow.tools.js +198 -0
  80. package/dist/tools/workflow.tools.js.map +1 -0
  81. package/package.json +3 -2
  82. package/server.json +3 -3
package/CAPABILITIES.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # MCP Dataverse Server — Complete Capabilities Reference
2
2
 
3
- > **Version**: 0.2.0 | **API Version**: Dataverse Web API v9.2 | **Transport**: MCP SDK over stdio
3
+ > **Version**: 0.3.1 | **API Version**: Dataverse Web API v9.2 | **Transport**: stdio · HTTP/SSE
4
4
 
5
- 50 tools across 22 categories for full Dataverse lifecycle: schema, CRUD, FetchXML, solutions, plugins, audit, files, users, teams, environment variables, and more.
5
+ 54 tools across 23 categories for full Dataverse lifecycle: schema, CRUD, FetchXML, solutions, plugins, audit, files, users, teams, environment variables, and more.
6
6
 
7
7
  ---
8
8
 
@@ -91,12 +91,12 @@ Server communicates over **stdio** (MCP SDK `StdioServerTransport`). Connect fro
91
91
 
92
92
  ```mermaid
93
93
  graph LR
94
- MCP["MCP Dataverse Server<br/><i>50 tools · 22 categories</i>"]
94
+ MCP["MCP Dataverse Server<br/><i>54 tools · 23 categories</i>"]
95
95
 
96
96
  MCP --> AUTH["🔑 Auth (1)"]
97
97
  MCP --> META["📋 Metadata (8)"]
98
98
  MCP --> QUERY["🔍 Query (3)"]
99
- MCP --> CRUD["✏️ CRUD (5)"]
99
+ MCP --> CRUD["✏️ CRUD (6)"]
100
100
  MCP --> REL["🔗 Relations (2)"]
101
101
  MCP --> ACT["⚡ Actions & Functions (6)"]
102
102
  MCP --> BATCH["📦 Batch (1)"]
@@ -114,6 +114,8 @@ graph LR
114
114
  MCP --> VIEWS["👁️ Views (1)"]
115
115
  MCP --> FILES["📁 Files (2)"]
116
116
  MCP --> ORG["🏢 Org (1)"]
117
+ MCP --> TEAMS["👥 Teams (1)"]
118
+ MCP --> ASSIST["🤖 Assistance (4)"]
117
119
  ```
118
120
 
119
121
  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.
package/README.md CHANGED
@@ -1,59 +1,53 @@
1
- # MCP Dataverse Server
1
+ # MCP Dataverse
2
2
 
3
- ![MCP Dataverse Logo](assets/logo.webp)
3
+ <div align="center">
4
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)
5
+ <img src="assets/logo.webp" alt="MCP Dataverse" width="180" />
6
6
 
7
- MCP server that exposes the Microsoft Dataverse Web API as **50 AI-callable tools** — enabling GitHub Copilot, Claude, and other MCP clients to query, create, and manage Dataverse records without hallucinating schema.
7
+ **The most complete MCP server for Microsoft Dataverse.**
8
8
 
9
- ## Install
9
+ 54 tools · 4 resources · 10 guided workflows · Zero config auth
10
10
 
11
- ### ✅ Recommended — Interactive CLI (VS Code 1.99+)
11
+ [![npm](https://img.shields.io/npm/v/mcp-dataverse)](https://www.npmjs.com/package/mcp-dataverse)
12
+ [![npm downloads](https://img.shields.io/npm/dm/mcp-dataverse)](https://www.npmjs.com/package/mcp-dataverse)
13
+ [![CI](https://github.com/codeurali/mcp-dataverse/actions/workflows/ci.yml/badge.svg)](https://github.com/codeurali/mcp-dataverse/actions/workflows/ci.yml)
14
+ [![Node 20+](https://img.shields.io/badge/Node.js-20%2B-green)](https://nodejs.org)
15
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.4-blue)](https://www.typescriptlang.org)
16
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow)](LICENSE)
12
17
 
13
- ```bash
14
- npx mcp-dataverse install
15
- ```
18
+ [Install](#install) · [Capabilities](#capabilities) · [Tools](#tools-54) · [Multi-Client Setup](docs/multi-client-setup.md) · [Full Reference](CAPABILITIES.md)
16
19
 
17
- The wizard will:
20
+ </div>
18
21
 
19
- 1. Ask for your Dataverse environment URL
20
- 2. Save configuration to `~/.mcp-dataverse/config.json`
21
- 3. Register the server in VS Code and/or VS Code Insiders via `code --add-mcp`
22
- 4. Authenticate with your Microsoft account (device code flow)
22
+ ---
23
23
 
24
- After the wizard completes, the server is immediately available in VS Code — open Copilot chat and the 50 Dataverse tools are ready.
24
+ ## Why MCP Dataverse?
25
25
 
26
- > **Requires VS Code 1.99+** the CLI registration uses `code --add-mcp`, introduced in March 2025. If neither `code` nor `code-insiders` is on your PATH, the wizard prints a manual snippet to copy-paste. Custom VS Code profiles are also detected and patched automatically.
26
+ AI agents hallucinate schema, guess column names, and build broken OData queries. This server gives them **real-time access** to your Dataverse environment schema, records, metadata, solutions through the Model Context Protocol.
27
27
 
28
- ---
28
+ - **No Azure AD app registration** — device code flow, zero pre-configuration
29
+ - **Works with any MCP client** — VS Code, Claude, Cursor, Windsurf, Gemini, Codex CLI
30
+ - **Atomic tools** — each tool does one thing well; the AI picks the right one
31
+ - **Structured outputs** — every response returns `{summary, data, suggestions}`
32
+ - **Guardrails** — destructive operations require explicit confirmation
33
+ - **Encrypted tokens** — AES-256-GCM cached credentials, never logged
29
34
 
30
- ### Alternative — VS Code Command Palette
35
+ ---
31
36
 
32
- 1. Press **Ctrl+Shift+P** (or **Cmd+Shift+P** on macOS)
33
- 2. Type **`MCP: Add Server`** → choose **`NPM Package`** → enter **`mcp-dataverse`**
34
- 3. Choose the scope: **User** or **Workspace**
35
- 4. Edit the generated entry to add your environment URL:
37
+ ## Install
36
38
 
37
- ```jsonc
38
- {
39
- "servers": {
40
- "mcp-dataverse": {
41
- "type": "stdio",
42
- "command": "npx",
43
- "args": ["-y", "mcp-dataverse"],
44
- "env": {
45
- "MCP_CONFIG_PATH": "/path/to/.mcp-dataverse/config.json"
46
- }
47
- }
48
- }
49
- }
39
+ ```bash
40
+ npx mcp-dataverse install
50
41
  ```
51
42
 
52
- ---
43
+ The interactive wizard configures your environment, registers the server in VS Code, and authenticates your Microsoft account. Done in under 2 minutes.
53
44
 
54
- ### Manual (mcp.json)
45
+ > Requires Node.js 20+ and VS Code 1.99+. For other clients (Claude, Cursor, Windsurf…), see [Multi-Client Setup](docs/multi-client-setup.md).
55
46
 
56
- Create or edit `.vscode/mcp.json` (workspace scope) or the user-level `mcp.json` (**Ctrl+Shift+P** → **MCP: Open User Configuration**):
47
+ <details>
48
+ <summary><strong>Manual setup (mcp.json)</strong></summary>
49
+
50
+ Add to `.vscode/mcp.json` or user-level MCP configuration:
57
51
 
58
52
  ```jsonc
59
53
  {
@@ -70,258 +64,169 @@ Create or edit `.vscode/mcp.json` (workspace scope) or the user-level `mcp.json`
70
64
  }
71
65
  ```
72
66
 
73
- ---
74
-
75
- ## Authentication — automatic, no setup required
76
-
77
- **No PAC CLI, no Azure AD app registration, no credentials to configure.**
78
-
79
- The server uses Microsoft's device code flow (MSAL Public Client) — the same mechanism used by Power Platform CLI. Zero pre-configuration: just set your environment URL and the server handles the rest.
80
-
81
- ### First connection — what you'll see
82
-
83
- Authentication is triggered on the **first tool call** after the server starts (e.g. asking Copilot _"Who am I in Dataverse?"_). Here is the exact sequence:
84
-
85
- **Step 1 — Open the Output panel**
86
-
87
- In VS Code: **View → Output** → select **MCP** in the dropdown.
88
-
89
- **Step 2 — The sign-in prompt appears**
90
-
91
- ```
92
- [mcp-dataverse] First-time authentication required.
93
- Environment: https://yourorg.crm.dynamics.com
94
- Open the URL below in your browser to sign in.
95
-
96
- [mcp-dataverse] Sign in required
97
-
98
- 1. Open https://microsoft.com/devicelogin in your browser
99
- (use the browser profile linked to your Power Platform account)
100
- 2. Paste the code: ABCD-1234 (already copied to your clipboard)
101
- 3. Sign in with your work account
102
- ```
103
-
104
- **Step 3 — Sign in**
105
-
106
- 1. Open `https://microsoft.com/devicelogin` in the browser/profile linked to your **Power Platform work account**
107
- 2. Paste the code — it's already in your clipboard
108
- 3. Complete Microsoft sign-in with your work account
109
-
110
- **Step 4 — Confirmation in the Output panel**
111
-
112
- ```
113
- [mcp-dataverse] Authenticated ✓ Token cached — no sign-in needed next time.
114
- ```
115
-
116
- The tool call that triggered auth now completes. All 50 tools are ready to use.
117
-
118
- > ⏱ The code expires after **5 minutes**. If it times out, retry the tool call — a new code will be generated.
67
+ </details>
119
68
 
120
- > **Why not auto-open the browser?** Consultants often work with multiple browser profiles (personal vs. work). Device code flow intentionally lets _you_ choose the right browser and profile.
121
-
122
- ### Subsequent launches
123
-
124
- The token is cached encrypted (AES-256-GCM) in `~/.mcp-dataverse/`. On all future server starts, renewal is **completely silent** — no prompt, no browser.
125
-
126
- You only need to re-authenticate if the refresh token expires (~90 days of inactivity) or you reset it manually:
127
-
128
- ```bash
129
- npx mcp-dataverse-auth https://yourorg.crm.dynamics.com
130
- ```
69
+ ---
131
70
 
132
- When re-auth is needed, the Output panel shows:
71
+ ## Authentication
133
72
 
134
- ```
135
- [mcp-dataverse] Session expired — re-authenticating.
136
- Open the URL below in your browser to sign in again.
73
+ **No PAC CLI, no app registration, no client secret.** The server uses Microsoft's device code flow (MSAL Public Client).
137
74
 
138
- [mcp-dataverse] Sign in required
139
- ...
140
- ```
75
+ 1. **First tool call** → a sign-in code appears in the Output panel (`View → Output → MCP`)
76
+ 2. Open `https://microsoft.com/devicelogin` → paste the code → sign in with your work account
77
+ 3. **Done.** Token is cached encrypted — all future starts are silent
141
78
 
142
- The same device code process applies.
79
+ Re-authentication is only needed after ~90 days of inactivity: `npx mcp-dataverse-auth`
143
80
 
144
81
  ---
145
82
 
146
- ## Prerequisites
83
+ ## Capabilities
147
84
 
148
- - Node.js 20+
149
- - VS Code + GitHub Copilot (Agent mode)
150
- - A Dataverse environment with a licensed user account
85
+ | Capability | Description |
86
+ |---|---|
87
+ | **54 Tools** | Full Dataverse lifecycle schema, CRUD, query, FetchXML, batch, search, audit, files, solutions, and more |
88
+ | **4 Resources** | `dataverse://tables`, schema templates, relationship templates, server instructions |
89
+ | **10 Workflows** | Guided multi-step sequences for common tasks (explore schema, create record, bulk operations…) |
90
+ | **Tool Router** | Intent-based tool suggestion — ask what you need, get the right tools |
91
+ | **Progress Notifications** | Real-time progress for paging and batch operations |
92
+ | **HTTP + SSE Transport** | Supports both stdio (default) and HTTP/SSE (`--transport http --port 3001`) |
151
93
 
152
- ## Quick Start (< 5 min)
153
-
154
- ### 1. Clone & install
155
-
156
- ```bash
157
- git clone <repo-url> mcp-dataverse && cd mcp-dataverse
158
- npm install
159
- ```
94
+ ---
160
95
 
161
- ### 2. Configure
96
+ ## Tools (54)
97
+
98
+ ### Core (50 tools)
99
+
100
+ | Category | Count | Tools |
101
+ |----------|-------|-------|
102
+ | **Metadata** | 8 | List tables, get schema, relationships, option sets, entity keys |
103
+ | **Query** | 3 | OData query, FetchXML, paginated retrieval |
104
+ | **CRUD** | 6 | Get, create, update, delete, upsert, assign |
105
+ | **Relations** | 2 | Associate, disassociate |
106
+ | **Actions & Functions** | 6 | Execute bound/unbound actions and functions, dependency checks |
107
+ | **Batch** | 1 | Up to 1000 operations in a single atomic request |
108
+ | **Solutions** | 3 | List solutions, components, publish customizations |
109
+ | **Customization** | 3 | Custom actions, plugin steps, workflow state |
110
+ | **Search** | 1 | Dataverse Relevance Search (full-text) |
111
+ | **Audit** | 1 | Record change history |
112
+ | **Trace** | 2 | Plugin trace logs, workflow execution logs |
113
+ | **Environment** | 2 | Get/set environment variables |
114
+ | **Users & Teams** | 3 | List users, roles, teams |
115
+ | **Files** | 2 | Upload/download file and image columns |
116
+ | **Annotations** | 2 | Notes and attachments (read + create) |
117
+ | **Views** | 1 | System and personal saved views |
118
+ | **Org** | 1 | Business units hierarchy |
119
+ | **Tracking** | 1 | Delta change detection with tokens |
120
+ | **Impersonation** | 1 | Execute any tool on behalf of another user |
121
+ | **Quality** | 1 | Duplicate detection |
122
+ | **Auth** | 1 | WhoAmI connection verification |
123
+
124
+ ### Assistance (4 tools)
125
+
126
+ | Tool | Purpose |
127
+ |------|---------|
128
+ | `dataverse_suggest_tools` | Describe your intent → get the right tools with usage examples |
129
+ | `dataverse_list_tool_tags` | Browse all tools by category tag |
130
+ | `dataverse_list_workflows` | List available guided workflows |
131
+ | `dataverse_get_workflow` | Get step-by-step instructions for a specific workflow |
132
+
133
+ > Full schema and parameter details → [CAPABILITIES.md](CAPABILITIES.md)
162
134
 
163
- ```bash
164
- cp config.example.json config.json
165
- ```
135
+ ---
166
136
 
167
- Edit `config.json`:
137
+ ## Architecture
168
138
 
169
- | Field | Description |
170
- | ------------------ | ----------------------------------------------------- |
171
- | `environmentUrl` | Your org URL, e.g. `https://yourorg.crm.dynamics.com` |
172
- | `requestTimeoutMs` | HTTP timeout in ms (default: `30000`) |
173
- | `maxRetries` | Retry count on transient errors (default: `3`) |
139
+ ```mermaid
140
+ flowchart LR
141
+ CLIENT["MCP Client\nCopilot · Claude · Cursor · Windsurf…"]
174
142
 
175
- ### 3. Authenticate
143
+ CLIENT -->|stdio / HTTP+SSE| SERVER
176
144
 
177
- ```bash
178
- npm run auth:setup
179
- ```
145
+ subgraph SERVER["MCP Server"]
146
+ direction TB
147
+ REGISTRY["Tool Registry — O(1) dispatch"]
148
+ TOOLS["54 Tools · 4 Resources"]
149
+ GUARD["Guardrails · Annotations · Structured Outputs"]
150
+ end
180
151
 
181
- Runs device code authentication. Follow the URL printed to the terminal — sign in with your Power Platform account. Token is cached and silently renewed.
152
+ SERVER --> HTTP
182
153
 
183
- ### 4. Build
154
+ subgraph HTTP["HTTP Layer"]
155
+ direction TB
156
+ HTTPC["HttpClient — native fetch · retry · timeout"]
157
+ AUTH["AuthProvider — MSAL device code flow"]
158
+ end
184
159
 
185
- ```bash
186
- npm run build
160
+ HTTP --> API["Dataverse\nWeb API v9.2"]
187
161
  ```
188
162
 
189
- ### 5. Verify the connection
163
+ **Stack**: TypeScript strict · Node.js 20+ · Zod validation · 459 tests · GitHub Actions CI
190
164
 
191
- ```bash
192
- npx tsx tests/live/test-whoami.ts
193
- ```
194
-
195
- Expected output:
196
-
197
- ```
198
- WhoAmI result: { UserId: 'xxxxxxxx-...', BusinessUnitId: 'xxxxxxxx-...', OrganizationId: 'xxxxxxxx-...' }
199
- ```
165
+ ---
200
166
 
201
- ### 6. Configure VS Code
167
+ ## Configuration
202
168
 
203
- `.vscode/mcp.json` is already present in this repo. If you need to add it manually:
169
+ `~/.mcp-dataverse/config.json` (created by the install wizard):
204
170
 
205
171
  ```json
206
172
  {
207
- "servers": {
208
- "dataverse": {
209
- "type": "stdio",
210
- "command": "node",
211
- "args": ["${workspaceFolder}/dist/server.js"],
212
- "env": {}
213
- }
214
- }
173
+ "environmentUrl": "https://yourorg.crm.dynamics.com",
174
+ "requestTimeoutMs": 30000,
175
+ "maxRetries": 3
215
176
  }
216
177
  ```
217
178
 
218
- 1. Restart VS Code
219
- 2. Open GitHub Copilot chat → switch to **Agent mode** (⚡)
220
- 3. Test: _"List the Dataverse tables in my environment"_
179
+ Config resolution: `MCP_CONFIG_PATH` env var → `~/.mcp-dataverse/config.json` `./config.json`
221
180
 
222
181
  ---
223
182
 
224
- ## Tools (50)
225
-
226
- | Tool | Category | Description |
227
- | -------------------------------------------- | ------------- | ----------------------------------------------------------------------------------- |
228
- | `dataverse_whoami` | Auth | Verify connection; returns UserId, BusinessUnitId, OrgId |
229
- | `dataverse_list_tables` | Metadata | List all tables (`customOnly` filter available) |
230
- | `dataverse_get_table_metadata` | Metadata | Full schema: columns, types, logical names |
231
- | `dataverse_get_relationships` | Metadata | All 1:N, N:1, N:N relationships for a table; filter by `relationshipType` |
232
- | `dataverse_list_global_option_sets` | Metadata | All global option sets in the environment |
233
- | `dataverse_get_option_set` | Metadata | Options and values for a specific option set |
234
- | `dataverse_get_entity_key` | Metadata | Alternate key definitions for a table (fields, index status, customizable flag) |
235
- | `dataverse_query` | Query | OData query with `$select`, `$filter`, `$orderby`, `$expand`, `$count` |
236
- | `dataverse_execute_fetchxml` | Query | Raw FetchXML for aggregations and complex joins |
237
- | `dataverse_retrieve_multiple_with_paging` | Query | Paginated query following `@odata.nextLink`, with configurable `maxTotal` cap |
238
- | `dataverse_get` | CRUD | Retrieve a single record by GUID |
239
- | `dataverse_create` | CRUD | Create a record; returns the new GUID |
240
- | `dataverse_update` | CRUD | Patch a record — only specified fields are changed |
241
- | `dataverse_delete` | CRUD | Delete a record (requires explicit confirm) |
242
- | `dataverse_upsert` | CRUD | Create-or-update via alternate key |
243
- | `dataverse_assign` | CRUD | Assign a record to a different user or team owner |
244
- | `dataverse_associate` | Relations | Associate two records via a named relationship |
245
- | `dataverse_disassociate` | Relations | Remove an association between two records |
246
- | `dataverse_execute_action` | Actions | Execute a global (unbound) Dataverse action |
247
- | `dataverse_execute_function` | Actions | Execute a global read-only function (e.g. `WhoAmI`) |
248
- | `dataverse_execute_bound_action` | Actions | Execute an action bound to a specific record |
249
- | `dataverse_execute_bound_function` | Actions | Execute an OData bound function on a specific record |
250
- | `dataverse_retrieve_dependencies_for_delete` | Actions | Check what components block deletion of a Dataverse component |
251
- | `dataverse_list_dependencies` | Actions | List component dependencies before modifying or deleting |
252
- | `dataverse_batch_execute` | Batch | Up to 1000 operations in a single HTTP batch request; optional atomic changeset |
253
- | `dataverse_change_detection` | Tracking | Delta tracking using change tokens to detect record changes since last sync |
254
- | `dataverse_solution_components` | Solution | List all components in a named solution; filter by component type code |
255
- | `dataverse_publish_customizations` | Solution | Publish pending customizations (all or targeted entities/web resources/option sets) |
256
- | `dataverse_impersonate` | Impersonation | Execute any tool on behalf of another Dataverse user via `MSCRMCallerId` |
257
- | `dataverse_list_custom_actions` | Customization | Lists custom actions (custom API / SDK messages) in the environment |
258
- | `dataverse_list_plugin_steps` | Customization | Lists plugin step registrations with stage, mode, entity, and state |
259
- | `dataverse_get_environment_variable` | Environment | Retrieve an environment variable definition and current value |
260
- | `dataverse_set_environment_variable` | Environment | Set or update an environment variable value |
261
- | `dataverse_get_plugin_trace_logs` | Trace | Retrieve plugin execution trace logs for debugging |
262
- | `dataverse_get_workflow_trace_logs` | Trace | Retrieve async workflow/system job execution logs |
263
- | `dataverse_search` | Search | Full-text Relevance Search across all configured tables |
264
- | `dataverse_get_audit_log` | Audit | Retrieve audit trail for a record showing change history |
265
- | `dataverse_detect_duplicates` | Quality | Check for potential duplicates before creating a record |
266
- | `dataverse_get_annotations` | Annotations | Retrieve notes and file attachments linked to a record |
267
- | `dataverse_list_users` | Users | Search system users by name or email with BU filtering |
268
- | `dataverse_get_user_roles` | Users | Security roles assigned to a system user |
269
- | `dataverse_create_annotation` | Annotations | Create a note or file attachment linked to a record |
270
- | `dataverse_get_attribute_option_set` | Metadata | Local/entity-specific option set values (statecode, statuscode, picklist) |
271
- | `dataverse_list_solutions` | Solution | List all solutions in the environment |
272
- | `dataverse_set_workflow_state` | Customization | Enable or disable a workflow or process |
273
- | `dataverse_list_views` | Views | List system and personal saved views for a table |
274
- | `dataverse_upload_file_column` | Files | Upload binary content to a file/image column on a record |
275
- | `dataverse_download_file_column` | Files | Download binary content from a file/image column on a record |
276
- | `dataverse_list_business_units` | Org | List business units in the environment (org hierarchy) |
277
- | `dataverse_list_teams` | Teams | List Dataverse teams with optional filter by team type |
183
+ ## CLI Commands
184
+
185
+ | Command | Description |
186
+ |---------|-------------|
187
+ | `npx mcp-dataverse install` | Interactive setup wizard |
188
+ | `npx mcp-dataverse doctor` | Diagnose configuration and connectivity issues |
189
+ | `npx mcp-dataverse-auth [url]` | Re-authenticate or switch environment |
190
+ | `npx mcp-dataverse --transport http --port 3001` | Start with HTTP/SSE transport |
278
191
 
279
192
  ---
280
193
 
281
- ## Scripts
194
+ ## Security
282
195
 
283
- | Command | Description |
284
- | -------------------------- | ----------------------------------- |
285
- | `npm run build` | Compile TypeScript `dist/` |
286
- | `npm run dev` | Watch mode no build step needed |
287
- | `npm start` | Start the compiled server |
288
- | `npm run auth:setup` | One-time device code authentication |
289
- | `npm run typecheck` | Type-check without emitting output |
290
- | `npm run lint` | ESLint on `src/` |
291
- | `npm run test:unit` | Unit tests only |
292
- | `npm run test:integration` | Integration tests |
293
- | `npm test` | All tests |
196
+ - **Zero credentials in code** — device code flow, no client secrets
197
+ - **Encrypted token cache** — AES-256-GCM in `~/.mcp-dataverse/`
198
+ - **Tokens never logged** only diagnostic messages on stderr
199
+ - **Destructive guardrails** delete operations require explicit `confirm: true`
200
+ - **User-scoped access** no privilege escalation beyond the authenticated user
201
+ - **Zod validation** all tool inputs validated at the boundary
294
202
 
295
203
  ---
296
204
 
297
- ## Architecture
298
-
299
- TypeScript MCP server over **stdio** transport. The `DeviceCodeAuthProvider` (MSAL device code flow) injects Bearer tokens into a native-`fetch`-based `HttpClient` wrapped by `DataverseClient`. Each tool module registers handlers with the MCP `Server` instance.
205
+ ## Troubleshooting
300
206
 
301
- ```
302
- GitHub Copilot → stdio → MCP Server → Tool Router → DataverseClient → Dataverse Web API v9.2
303
- └── DeviceCodeAuthProvider (MSAL)
304
- ```
207
+ | Symptom | Fix |
208
+ |---------|-----|
209
+ | No sign-in prompt | Open **View → Output → MCP** — the device code is displayed there |
210
+ | `No MSAL accounts found` | Run `npx mcp-dataverse-auth` then restart the server |
211
+ | `Authentication timed out` | The 5-minute window expired — restart the MCP server for a new code |
212
+ | Server not appearing in Agent mode | Run `npx mcp-dataverse install` or `npx mcp-dataverse doctor` |
213
+ | HTTP errors | Run `npx mcp-dataverse doctor` to check config, auth, and connectivity |
305
214
 
306
215
  ---
307
216
 
308
- ## Security
217
+ ## Contributing
309
218
 
310
- - **Never commit `config.json`** — it is in `.gitignore`
311
- - Token cache (`~/.mcp-dataverse/`) is encrypted (AES-256-GCM) and should not be shared
312
- - Tokens are never logged; only diagnostic messages are written to stderr
313
- - Tokens are scoped to the authenticated user — no privilege escalation
219
+ ```bash
220
+ git clone https://github.com/codeurali/mcp-dataverse.git && cd mcp-dataverse
221
+ npm install
222
+ npm run build
223
+ npm test # 459 tests across 38 suites
224
+ npm run lint # ESLint strict
225
+ npm run typecheck # TypeScript strict mode
226
+ ```
314
227
 
315
228
  ---
316
229
 
317
- ## Troubleshooting
230
+ ## License
318
231
 
319
- | Symptom | Fix |
320
- | ------------------------------------------ | -------------------------------------------------------------------------------- |
321
- | No sign-in prompt appeared | Open **View → Output → MCP** in VS Code — the device code is displayed there |
322
- | Browser didn't open automatically | Copy the URL from the Output panel manually: `https://microsoft.com/devicelogin` |
323
- | `No MSAL accounts found` | Run `npx mcp-dataverse-auth` to re-authenticate, then restart the server |
324
- | `Authentication timed out` | The 5-minute window expired — restart the MCP server to get a new code |
325
- | `"https://" is required` | Check your `~/.mcp-dataverse/config.json` — URL must start with `https://` |
326
- | Server not appearing in Copilot Agent mode | Re-run `npx mcp-dataverse install`; check **Output → MCP** panel for errors |
327
- | Install wizard says "not found on PATH" | Install VS Code Shell Command (**Ctrl+Shift+P** → *Shell Command: Install...*) or use the manual snippet provided |
232
+ [MIT](LICENSE) © [codeurali](https://github.com/codeurali)
Binary file
@@ -0,0 +1,11 @@
1
+ import type { Resource, ResourceTemplate } from "@modelcontextprotocol/sdk/types.js";
2
+ import type { DataverseAdvancedClient } from "../dataverse/dataverse-client-advanced.js";
3
+ export interface ResourceContent {
4
+ uri: string;
5
+ mimeType: string;
6
+ text: string;
7
+ }
8
+ export declare function listResources(): Resource[];
9
+ export declare function listResourceTemplates(): ResourceTemplate[];
10
+ export declare function readResource(uri: string, client: DataverseAdvancedClient, serverInstructions: string): Promise<ResourceContent>;
11
+ //# sourceMappingURL=resource-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-provider.d.ts","sourceRoot":"","sources":["../../src/resources/resource-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AA8EzF,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,IAAI,QAAQ,EAAE,CAE1C;AAED,wBAAgB,qBAAqB,IAAI,gBAAgB,EAAE,CAE1D;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,uBAAuB,EAC/B,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAAC,eAAe,CAAC,CAoB1B"}
@@ -0,0 +1,79 @@
1
+ // ── Resource Templates (dynamic URIs with parameters) ────────────────────────
2
+ const RESOURCE_TEMPLATES = [
3
+ {
4
+ uriTemplate: "dataverse://tables/{tableName}/schema",
5
+ name: "Table Schema",
6
+ description: "Returns the full schema (columns, types, requirements) for a Dataverse table",
7
+ mimeType: "application/json",
8
+ },
9
+ {
10
+ uriTemplate: "dataverse://tables/{tableName}/relationships",
11
+ name: "Table Relationships",
12
+ description: "Returns all 1:N and N:N relationships for a Dataverse table",
13
+ mimeType: "application/json",
14
+ },
15
+ ];
16
+ // ── Static Resources (fixed URIs) ────────────────────────────────────────────
17
+ const STATIC_RESOURCES = [
18
+ {
19
+ uri: "dataverse://tables",
20
+ name: "Available Tables",
21
+ description: "Lists all custom tables in the connected Dataverse environment",
22
+ mimeType: "application/json",
23
+ },
24
+ {
25
+ uri: "dataverse://server/instructions",
26
+ name: "Server Instructions",
27
+ description: "Usage guidelines and best practices for interacting with this Dataverse MCP server",
28
+ mimeType: "text/plain",
29
+ },
30
+ ];
31
+ function parseResourceUri(uri) {
32
+ const PREFIX = "dataverse://";
33
+ if (!uri.startsWith(PREFIX)) {
34
+ throw new Error(`Unknown resource URI: ${uri}`);
35
+ }
36
+ const path = uri.slice(PREFIX.length);
37
+ if (path === "tables") {
38
+ return { type: "tables" };
39
+ }
40
+ if (path === "server/instructions") {
41
+ return { type: "instructions" };
42
+ }
43
+ const schemaMatch = /^tables\/([^/]+)\/schema$/.exec(path);
44
+ if (schemaMatch) {
45
+ return { type: "schema", tableName: schemaMatch[1] };
46
+ }
47
+ const relMatch = /^tables\/([^/]+)\/relationships$/.exec(path);
48
+ if (relMatch) {
49
+ return { type: "relationships", tableName: relMatch[1] };
50
+ }
51
+ throw new Error(`Unknown resource URI: ${uri}`);
52
+ }
53
+ export function listResources() {
54
+ return STATIC_RESOURCES;
55
+ }
56
+ export function listResourceTemplates() {
57
+ return RESOURCE_TEMPLATES;
58
+ }
59
+ export async function readResource(uri, client, serverInstructions) {
60
+ const parsed = parseResourceUri(uri);
61
+ switch (parsed.type) {
62
+ case "tables": {
63
+ const tables = await client.listTables(true);
64
+ return { uri, mimeType: "application/json", text: JSON.stringify(tables, null, 2) };
65
+ }
66
+ case "schema": {
67
+ const metadata = await client.getTableMetadata(parsed.tableName);
68
+ return { uri, mimeType: "application/json", text: JSON.stringify(metadata, null, 2) };
69
+ }
70
+ case "relationships": {
71
+ const rels = await client.getRelationships(parsed.tableName);
72
+ return { uri, mimeType: "application/json", text: JSON.stringify(rels, null, 2) };
73
+ }
74
+ case "instructions": {
75
+ return { uri, mimeType: "text/plain", text: serverInstructions };
76
+ }
77
+ }
78
+ }
79
+ //# sourceMappingURL=resource-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-provider.js","sourceRoot":"","sources":["../../src/resources/resource-provider.ts"],"names":[],"mappings":"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"}