mcp-dataverse 0.4.5 → 0.4.7
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.
- package/CAPABILITIES.md +92 -33
- package/README.md +1 -1
- package/dist/chunk-FSM3J3WD.js +35 -0
- package/dist/dataverse-client-advanced-EASNSX3M.js +1 -0
- package/dist/doctor.js +1 -1
- package/dist/server.js +22 -11
- package/package.json +2 -2
- package/server.json +3 -3
- package/dist/chunk-MPWVUZBX.js +0 -35
- package/dist/dataverse-client-advanced-ZG4OPCGR.js +0 -1
package/CAPABILITIES.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# MCP Dataverse Server — Complete Capabilities Reference
|
|
2
2
|
|
|
3
|
-
> **Version**: 0.4.
|
|
3
|
+
> **Version**: 0.4.6 | **API Version**: Dataverse Web API v9.2 | **Transport**: stdio · HTTP/SSE
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
73 tools across 25 categories for full Dataverse lifecycle: schema, CRUD, FetchXML, solutions, plugins, audit, files, users, teams, RBAC, attribute management, environment variables, workflows, and more.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -10,19 +10,19 @@
|
|
|
10
10
|
|
|
11
11
|
- [Quick Start](#quick-start)
|
|
12
12
|
- [Architecture Overview](#architecture-overview)
|
|
13
|
-
- [Tool Reference (
|
|
13
|
+
- [Tool Reference (73 tools)](#tool-reference-73-tools)
|
|
14
14
|
- [1. Auth (1)](#1-auth-1-tool)
|
|
15
|
-
- [2. Metadata (
|
|
15
|
+
- [2. Metadata (9)](#2-metadata-9-tools)
|
|
16
16
|
- [3. Query (3)](#3-query-3-tools)
|
|
17
|
-
- [4. CRUD (
|
|
18
|
-
- [5. Relations (
|
|
17
|
+
- [4. CRUD (6)](#4-crud-6-tools)
|
|
18
|
+
- [5. Relations (4)](#5-relations-4-tools)
|
|
19
19
|
- [6. Actions & Functions (6)](#6-actions--functions-6-tools)
|
|
20
20
|
- [7. Batch (1)](#7-batch-1-tool)
|
|
21
21
|
- [8. Change Tracking (1)](#8-change-tracking-1-tool)
|
|
22
|
-
- [9. Solutions (
|
|
22
|
+
- [9. Solutions (2)](#9-solutions-2-tools)
|
|
23
23
|
- [10. Impersonation (1)](#10-impersonation-1-tool)
|
|
24
|
-
- [11. Customization (
|
|
25
|
-
- [12. Environment (
|
|
24
|
+
- [11. Customization (4)](#11-customization-4-tools)
|
|
25
|
+
- [12. Environment (4)](#12-environment-4-tools)
|
|
26
26
|
- [13. Trace (2)](#13-trace-2-tools)
|
|
27
27
|
- [14. Search (1)](#14-search-1-tool)
|
|
28
28
|
- [15. Audit (1)](#15-audit-1-tool)
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
- [18. Users (2)](#18-users-2-tools)
|
|
32
32
|
- [19. Views (1)](#19-views-1-tool)
|
|
33
33
|
- [20. Files (2)](#20-files-2-tools)
|
|
34
|
-
- [21. Org (
|
|
35
|
-
- [22. RBAC (
|
|
36
|
-
- [23. Workflows (
|
|
37
|
-
- [24. Assistance (
|
|
34
|
+
- [21. Org (2)](#21-org-2-tools)
|
|
35
|
+
- [22. RBAC (7)](#22-rbac-7-tools)
|
|
36
|
+
- [23. Workflows (4)](#23-workflows-4-tools)
|
|
37
|
+
- [24. Assistance (2)](#24-assistance-2-tools)
|
|
38
38
|
- [25. Attributes (4)](#25-attributes-4-tools)
|
|
39
39
|
- [Error Handling & Retry Behavior](#error-handling--retry-behavior)
|
|
40
40
|
- [Security](#security)
|
|
@@ -95,32 +95,32 @@ Server communicates over **stdio** (MCP SDK `StdioServerTransport`). Connect fro
|
|
|
95
95
|
|
|
96
96
|
```mermaid
|
|
97
97
|
graph LR
|
|
98
|
-
MCP["MCP Dataverse Server<br/><i>
|
|
98
|
+
MCP["MCP Dataverse Server<br/><i>73 tools · 25 categories</i>"]
|
|
99
99
|
|
|
100
100
|
MCP --> AUTH["🔑 Auth (1)"]
|
|
101
|
-
MCP --> META["📋 Metadata (
|
|
101
|
+
MCP --> META["📋 Metadata (9)"]
|
|
102
102
|
MCP --> QUERY["🔍 Query (3)"]
|
|
103
103
|
MCP --> CRUD["✏️ CRUD (6)"]
|
|
104
|
-
MCP --> REL["🔗 Relations (
|
|
104
|
+
MCP --> REL["🔗 Relations (4)"]
|
|
105
105
|
MCP --> ACT["⚡ Actions & Functions (6)"]
|
|
106
106
|
MCP --> BATCH["📦 Batch (1)"]
|
|
107
107
|
MCP --> TRACK["🔄 Change Tracking (1)"]
|
|
108
|
-
MCP --> SOL["🧩 Solutions (
|
|
108
|
+
MCP --> SOL["🧩 Solutions (2)"]
|
|
109
109
|
MCP --> IMP["👤 Impersonation (1)"]
|
|
110
|
-
MCP --> CUST["🔧 Customization (
|
|
111
|
-
MCP --> ENV["⚙️ Environment (
|
|
110
|
+
MCP --> CUST["🔧 Customization (4)"]
|
|
111
|
+
MCP --> ENV["⚙️ Environment (4)"]
|
|
112
112
|
MCP --> TRACE["🔎 Trace (2)"]
|
|
113
113
|
MCP --> SRCH["🔍 Search (1)"]
|
|
114
114
|
MCP --> AUDIT["📜 Audit (1)"]
|
|
115
115
|
MCP --> QUAL["✅ Quality (1)"]
|
|
116
116
|
MCP --> NOTE["📝 Annotations (2)"]
|
|
117
117
|
MCP --> USR["👥 Users (2)"]
|
|
118
|
-
MCP --> RBAC["🛡️ RBAC (
|
|
118
|
+
MCP --> RBAC["🛡️ RBAC (7)"]
|
|
119
119
|
MCP --> VIEWS["👁️ Views (1)"]
|
|
120
120
|
MCP --> FILES["📁 Files (2)"]
|
|
121
121
|
MCP --> ORG["🏢 Org (2)"]
|
|
122
|
-
MCP --> WF["⚙️ Workflows (
|
|
123
|
-
MCP --> ASSIST["🤖 Assistance (
|
|
122
|
+
MCP --> WF["⚙️ Workflows (4)"]
|
|
123
|
+
MCP --> ASSIST["🤖 Assistance (2)"]
|
|
124
124
|
MCP --> ATTR["🏗️ Attributes (4)"]
|
|
125
125
|
```
|
|
126
126
|
|
|
@@ -128,7 +128,7 @@ All tool handlers validate inputs with **Zod** before calling the `DataverseAdva
|
|
|
128
128
|
|
|
129
129
|
---
|
|
130
130
|
|
|
131
|
-
## Tool Reference (
|
|
131
|
+
## Tool Reference (73 tools)
|
|
132
132
|
|
|
133
133
|
### 1. Auth (1 tool)
|
|
134
134
|
|
|
@@ -140,7 +140,7 @@ Returns the current authenticated user context (userId, businessUnitId, organiza
|
|
|
140
140
|
|
|
141
141
|
---
|
|
142
142
|
|
|
143
|
-
### 2. Metadata (
|
|
143
|
+
### 2. Metadata (9 tools)
|
|
144
144
|
|
|
145
145
|
#### `dataverse_list_tables`
|
|
146
146
|
|
|
@@ -279,7 +279,7 @@ Retrieves ALL matching records by auto-following `@odata.nextLink` pages. Use wh
|
|
|
279
279
|
|
|
280
280
|
---
|
|
281
281
|
|
|
282
|
-
### 4. CRUD (
|
|
282
|
+
### 4. CRUD (6 tools)
|
|
283
283
|
|
|
284
284
|
#### `dataverse_get`
|
|
285
285
|
|
|
@@ -360,7 +360,22 @@ Create-or-update via an alternate key (no GUID needed). Returns `"created"` or `
|
|
|
360
360
|
|
|
361
361
|
---
|
|
362
362
|
|
|
363
|
-
|
|
363
|
+
#### `dataverse_assign`
|
|
364
|
+
|
|
365
|
+
Assigns a Dataverse record to a different user or team owner. Sets the `ownerid` lookup field using OData bind syntax.
|
|
366
|
+
|
|
367
|
+
| Parameter | Type | Req | Notes |
|
|
368
|
+
| --------------- | ---------------------- | --- | ----------------------- |
|
|
369
|
+
| `entitySetName` | `string` | ✓ | OData entity set name |
|
|
370
|
+
| `id` | `string (UUID)` | ✓ | Record GUID to reassign |
|
|
371
|
+
| `ownerType` | `"systemuser"\|"team"` | ✓ | Target owner type |
|
|
372
|
+
| `ownerId` | `string (UUID)` | ✓ | GUID of user or team |
|
|
373
|
+
|
|
374
|
+
> "Reassign account a1b2c3d4 to user u1v2w3x4"
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
### 5. Relations (4 tools)
|
|
364
379
|
|
|
365
380
|
#### `dataverse_associate`
|
|
366
381
|
|
|
@@ -520,7 +535,7 @@ Delta-query for incremental sync. Pass `deltaToken: null` for initial snapshot;
|
|
|
520
535
|
|
|
521
536
|
---
|
|
522
537
|
|
|
523
|
-
### 9. Solutions (
|
|
538
|
+
### 9. Solutions (2 tools)
|
|
524
539
|
|
|
525
540
|
#### `dataverse_list_solutions`
|
|
526
541
|
|
|
@@ -597,7 +612,7 @@ Executes any other tool on behalf of a different Dataverse user by injecting `MS
|
|
|
597
612
|
|
|
598
613
|
---
|
|
599
614
|
|
|
600
|
-
### 11. Customization (
|
|
615
|
+
### 11. Customization (4 tools)
|
|
601
616
|
|
|
602
617
|
#### `dataverse_list_custom_actions`
|
|
603
618
|
|
|
@@ -657,7 +672,7 @@ Activates or deactivates a classic Dataverse workflow (statecode/statuscode upda
|
|
|
657
672
|
|
|
658
673
|
---
|
|
659
674
|
|
|
660
|
-
### 12. Environment (
|
|
675
|
+
### 12. Environment (4 tools)
|
|
661
676
|
|
|
662
677
|
#### `dataverse_get_environment_variable`
|
|
663
678
|
|
|
@@ -694,6 +709,24 @@ Sets or updates an environment variable's current value (creates or updates the
|
|
|
694
709
|
|
|
695
710
|
---
|
|
696
711
|
|
|
712
|
+
#### `dataverse_create_environment_variable`
|
|
713
|
+
|
|
714
|
+
Creates a new Dataverse environment variable definition and sets its initial value. Use when the variable does not yet exist.
|
|
715
|
+
|
|
716
|
+
| Parameter | Type | Req | Notes |
|
|
717
|
+
| -------------- | ---------------------------------------- | --- | ------------------------------------------------------- |
|
|
718
|
+
| `schemaName` | `string` | ✓ | Schema name (publisher prefix required, e.g. `new_MyVar`) |
|
|
719
|
+
| `displayName` | `string` | ✓ | Human-readable label |
|
|
720
|
+
| `type` | `"String"\|"Integer"\|"Boolean"\|"JSON"` | ✓ | Variable data type |
|
|
721
|
+
| `value` | `string` | ✓ | Initial value |
|
|
722
|
+
| `description` | `string` | — | Optional description |
|
|
723
|
+
| `defaultValue` | `string` | — | Optional default value |
|
|
724
|
+
| `confirm` | `true` | ✓ | Explicit confirmation required |
|
|
725
|
+
|
|
726
|
+
> "Create environment variable new_MaxRetries of type Integer with value 3"
|
|
727
|
+
|
|
728
|
+
---
|
|
729
|
+
|
|
697
730
|
### 13. Trace (2 tools)
|
|
698
731
|
|
|
699
732
|
#### `dataverse_get_plugin_trace_logs`
|
|
@@ -977,7 +1010,7 @@ Lists Dataverse teams (owner teams and access teams) within one or all business
|
|
|
977
1010
|
|
|
978
1011
|
---
|
|
979
1012
|
|
|
980
|
-
### 22. RBAC (
|
|
1013
|
+
### 22. RBAC (7 tools)
|
|
981
1014
|
|
|
982
1015
|
#### `dataverse_list_roles`
|
|
983
1016
|
|
|
@@ -1025,7 +1058,21 @@ Removes a security role from a system user.
|
|
|
1025
1058
|
|
|
1026
1059
|
---
|
|
1027
1060
|
|
|
1028
|
-
|
|
1061
|
+
#### `dataverse_assign_role_to_team`
|
|
1062
|
+
|
|
1063
|
+
Assigns a security role to a Dataverse team. All team members inherit the role permissions.
|
|
1064
|
+
|
|
1065
|
+
| Parameter | Type | Req | Notes |
|
|
1066
|
+
| --------- | --------------- | --- | ------------------------------ |
|
|
1067
|
+
| `teamId` | `string (UUID)` | ✓ | Team GUID |
|
|
1068
|
+
| `roleId` | `string (UUID)` | ✓ | Security role GUID |
|
|
1069
|
+
| `confirm` | `true` | ✓ | Explicit confirmation required |
|
|
1070
|
+
|
|
1071
|
+
> "Assign role r1s2t3u4 to team t1e2a3m4"
|
|
1072
|
+
|
|
1073
|
+
---
|
|
1074
|
+
|
|
1075
|
+
### 23. Workflows (4 tools)
|
|
1029
1076
|
|
|
1030
1077
|
#### `dataverse_list_workflows`
|
|
1031
1078
|
|
|
@@ -1053,7 +1100,7 @@ Retrieves a single workflow definition by ID, including its trigger, steps, and
|
|
|
1053
1100
|
|
|
1054
1101
|
---
|
|
1055
1102
|
|
|
1056
|
-
### 24. Assistance (
|
|
1103
|
+
### 24. Assistance (2 tools)
|
|
1057
1104
|
|
|
1058
1105
|
#### `dataverse_suggest_tools`
|
|
1059
1106
|
|
|
@@ -1105,6 +1152,18 @@ Lists connection references used in solutions (Power Automate connectors).
|
|
|
1105
1152
|
|
|
1106
1153
|
---
|
|
1107
1154
|
|
|
1155
|
+
#### `dataverse_list_tool_tags`
|
|
1156
|
+
|
|
1157
|
+
Lists all available tool tags with the number of tools in each category. Use this to discover what kinds of operations are available before calling `dataverse_suggest_tools`.
|
|
1158
|
+
|
|
1159
|
+
| Parameter | Type | Req | Notes |
|
|
1160
|
+
| --------- | ---- | --- | ------------- |
|
|
1161
|
+
| — | — | — | No parameters |
|
|
1162
|
+
|
|
1163
|
+
> "What categories of tools are available in this MCP server?"
|
|
1164
|
+
|
|
1165
|
+
---
|
|
1166
|
+
|
|
1108
1167
|
### 25. Attributes (4 tools)
|
|
1109
1168
|
|
|
1110
1169
|
Attribute tools manage **column-level schema** in Dataverse tables. All write operations require `confirm: true` and auto-publish the entity definition by default.
|
|
@@ -1301,4 +1360,4 @@ Certain tools include an `errorCategory` field in the error text when the failur
|
|
|
1301
1360
|
|
|
1302
1361
|
---
|
|
1303
1362
|
|
|
1304
|
-
_This document reflects the MCP Dataverse server codebase as of v0.4.
|
|
1363
|
+
_This document reflects the MCP Dataverse server codebase as of v0.4.6 — 73 tools across 25 categories._
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**The most complete MCP server for Microsoft Dataverse.**
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
73 tools · 4 resources · 10 guided workflows · Zero config auth
|
|
10
10
|
|
|
11
11
|
[](https://www.npmjs.com/package/mcp-dataverse)
|
|
12
12
|
[](https://www.npmjs.com/package/mcp-dataverse)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var y=class extends Error{constructor(e,n,s,r,i={}){super(e);this.status=n;this.data=s;this.code=r;this.responseHeaders=i;this.name="HttpError"}},R=class{baseURL;timeoutMs;defaultHeaders;tokenProvider;constructor(t){this.baseURL=t.baseURL.endsWith("/")?t.baseURL:t.baseURL+"/",this.timeoutMs=t.timeout??3e4,this.defaultHeaders={...t.headers},this.tokenProvider=t.tokenProvider??void 0}async get(t,e){return this.request("GET",t,void 0,e)}async post(t,e,n){return this.request("POST",t,e,n)}async patch(t,e,n){return this.request("PATCH",t,e,n)}async put(t,e,n){return this.request("PUT",t,e,n)}async delete(t,e){return this.request("DELETE",t,void 0,e)}resolveUrl(t){if(!t.startsWith("http"))return this.baseURL+t;let e=new URL(t),n=new URL(this.baseURL);if(e.origin!==n.origin)throw new y(`SSRF protection: request to '${e.origin}' blocked; only '${n.origin}' is permitted`,0,void 0,"SSRF_BLOCKED");return t}async request(t,e,n,s){let r=this.resolveUrl(e),i={...this.defaultHeaders,...s?.headers};this.tokenProvider&&(i.Authorization=`Bearer ${await this.tokenProvider()}`);let c=s?.timeoutMs??this.timeoutMs,u=new AbortController,a=setTimeout(()=>u.abort(),c);try{let o={method:t,headers:i,signal:u.signal};n!==void 0&&(o.body=typeof n=="string"?n:JSON.stringify(n));let d=await fetch(r,o),p={};if(d.headers.forEach((g,f)=>{p[f]=g}),!d.ok){let g=await d.text(),f;try{f=JSON.parse(g)}catch{f=g||void 0}throw new y(`Request failed with status ${d.status}`,d.status,f,void 0,p)}let m;if(s?.responseType==="text")m=await d.text();else{let g=await d.text();m=g?JSON.parse(g):{}}return{data:m,status:d.status,headers:p}}catch(o){throw o instanceof y?o:o instanceof DOMException&&o.name==="AbortError"?new y("Request timed out",0,void 0,"ECONNABORTED"):o}finally{clearTimeout(a)}}};function O(h){let t=h.indexOf(`\r
|
|
2
|
+
\r
|
|
3
|
+
`),e=h.indexOf(`
|
|
4
|
+
|
|
5
|
+
`);return t!==-1&&(e===-1||t<=e)?t+4:e!==-1?e+2:-1}function v(h,t){let e=[],n=h.split(`--${t}`);for(let s of n){let r=s.trim();if(!r||r==="--")continue;let i=O(s);if(i===-1)continue;let c=s.slice(i),u=O(c);if(u===-1)continue;let o=(c.trimStart().split(/\r?\n/)[0]??"").match(/^HTTP\/\d+\.\d+\s+(\d{3})/),d=o?parseInt(o[1],10):0,p=d>=200&&d<300,m=c.slice(u).trim();if(!m){e.push(p?null:{error:"Empty response body",status:d});continue}try{let g=JSON.parse(m);e.push(p?g:{error:g,status:d})}catch{e.push({error:m,status:d})}}return e}function l(h){return h.replace(/'/g,"''")}var P="9.2",x={opportunities:"opportunityid",territories:"territoryid",categories:"categoryid",activityparties:"activitypartyid",activitymimeattachments:"activitymimeattachmentid",queues:"queueid",queueitems:"queueitemid"},$=class{http;authProvider;maxRetries;constructor(t,e=3,n=3e4){this.authProvider=t,this.maxRetries=e,this.http=new R({baseURL:`${t.environmentUrl}/api/data/v${P}/`,timeout:n,headers:{"OData-MaxVersion":"4.0","OData-Version":"4.0",Accept:"application/json","Content-Type":"application/json; charset=utf-8"},tokenProvider:()=>t.getToken()})}async requestWithRetry(t,e=0){try{return await t()}catch(n){if(n instanceof y){if(n.status===401&&e===0)return this.authProvider.invalidateToken(),this.requestWithRetry(t,e+1);if([429,503,504].includes(n.status)&&e<this.maxRetries){let r=n.responseHeaders["retry-after"],i=r?parseInt(r,10)*1e3:Math.pow(2,e)*1e3;return await new Promise(c=>setTimeout(c,i)),this.requestWithRetry(t,e+1)}if(n.status===400){let r=n.data?.error?.code;if(r==="0x80071151"&&e<5){let u=Math.pow(2,e)*5e3;return await new Promise(a=>setTimeout(a,u)),this.requestWithRetry(t,e+1)}let i=n.data?.error?.message?.toLowerCase()??"";if((r==="0x80044181"||i.includes("publish")&&(i.includes("already")||i.includes("in progress")||i.includes("another user")))&&e<4)return await new Promise(u=>setTimeout(u,3e4)),this.requestWithRetry(t,e+1)}}throw this.formatError(n)}}formatError(t){if(t instanceof y){let e=t.data?.error;return e?.code==="0x80060888"?new Error(`Dataverse error 0x80060888: The Web API endpoint does not exist in this organization. This means the action/function name is wrong OR the entity set name is incorrect \u2014 NOT necessarily a permissions error. Original message: ${e.message??""}. Tip: verify action names via $metadata or use dataverse_resolve_entity_name for entity names.`):e?new Error(`Dataverse error ${e.code??""}: ${e.message??"Unknown error"}`):t.code==="ECONNABORTED"?new Error("Request timed out. Check your Dataverse environment URL."):t}return t instanceof Error?t:new Error(String(t))}async whoAmI(){return this.requestWithRetry(async()=>{let t=await this.http.get("WhoAmI"),{UserId:e,BusinessUnitId:n,OrganizationId:s}=t.data,r="";try{r=(await this.http.get(`organizations(${s})?$select=name`)).data.name??""}catch{r=""}let i=this.authProvider.environmentUrl;return{UserId:e,BusinessUnitId:n,OrganizationId:s,OrganizationName:r,EnvironmentUrl:i}})}async listTables(t=!1){let s=["$select=LogicalName,SchemaName,DisplayName,EntitySetName,PrimaryIdAttribute,PrimaryNameAttribute,IsCustomEntity",t?"$filter=IsCustomEntity eq true":""].filter(Boolean).join("&");return this.requestWithRetry(()=>this.http.get(`EntityDefinitions?${s}`).then(r=>r.data.value))}async getTableMetadata(t,e=!0){let n=e?"$expand=Attributes":"",s=`EntityDefinitions(LogicalName='${l(t)}')${n?"?"+n:""}`;return this.requestWithRetry(()=>this.http.get(s).then(r=>r.data))}async fetchAllPagesOData(t){let e=[],n=t;for(;n;){let s=await this.requestWithRetry(()=>this.http.get(n).then(r=>r.data));e.push(...s.value??[]),n=s["@odata.nextLink"]}return e}async getRelationships(t){let e=l(t),[n,s,r]=await Promise.all([this.fetchAllPagesOData(`EntityDefinitions(LogicalName='${e}')/OneToManyRelationships`),this.fetchAllPagesOData(`EntityDefinitions(LogicalName='${e}')/ManyToOneRelationships`),this.fetchAllPagesOData(`EntityDefinitions(LogicalName='${e}')/ManyToManyRelationships`)]);return[...n,...s,...r]}async query(t,e={}){let n=c=>encodeURIComponent(c).replace(/%28/g,"(").replace(/%29/g,")").replace(/%2C/g,",").replace(/%27/g,"'").replace(/%40/g,"@"),s=[];e.select?.length&&s.push(`$select=${e.select.join(",")}`),e.filter&&s.push(`$filter=${n(e.filter)}`),e.orderby&&s.push(`$orderby=${n(e.orderby)}`),e.top&&s.push(`$top=${e.top}`),e.expand&&s.push(`$expand=${e.expand}`),e.count&&s.push("$count=true"),e.apply&&s.push(`$apply=${n(e.apply)}`);let r=`${t}${s.length?"?"+s.join("&"):""}`,i=e.formattedValues?{headers:{Prefer:'odata.include-annotations="OData.Community.Display.V1.FormattedValue"'}}:void 0;return this.requestWithRetry(()=>this.http.get(r,i).then(c=>c.data))}async executeFetchXml(t,e,n){let s=encodeURIComponent(e),r=n?{headers:{Prefer:'odata.include-annotations="OData.Community.Display.V1.FormattedValue"'}}:void 0;return this.requestWithRetry(()=>this.http.get(`${t}?fetchXml=${s}`,r).then(i=>i.data))}async getRecord(t,e,n,s){let r=[];n?.length&&r.push(`$select=${n.join(",")}`),s&&r.push(`$expand=${s}`);let i=r.length?`?${r.join("&")}`:"";return this.requestWithRetry(async()=>{let c=await this.http.get(`${t}(${e})${i}`,{headers:{Prefer:'odata.include-annotations="*"'}}),u=c.headers["odata-etag"]??c.data["@odata.etag"]??null;return{record:c.data,etag:u}})}async createRecord(t,e){return this.requestWithRetry(async()=>{let n=await this.http.post(t,e,{headers:{Prefer:"return=representation"}}),r=n.headers["odata-entityid"]?.match(/\(([^)]+)\)/)?.[1];if(r)return r;let i=n.data,c=i["@odata.id"]?.match(/\(([^)]+)\)/)?.[1];if(c)return c;let u=x[t]??t.replace(/s$/,"")+"id",a=i[u];return a||(n.headers.location?.match(/\(([^)]+)\)/)?.[1]??"")})}async updateRecord(t,e,n,s){await this.requestWithRetry(()=>this.http.patch(`${t}(${e})`,n,{headers:{"If-Match":s??"*"}}))}async deleteRecord(t,e){await this.requestWithRetry(()=>this.http.delete(`${t}(${e})`))}async upsertRecord(t,e,n,s,r="upsert",i){return this.requestWithRetry(async()=>{let c=i?`${t}(${i})`:`${t}(${l(e)}='${l(n)}')`,u={Prefer:"return=representation"};r==="createOnly"&&(u["If-None-Match"]="*"),r==="updateOnly"&&(u["If-Match"]="*");try{let a=await this.http.put(c,s,{headers:u}),o=a.status===201?"created":"updated",p=a.headers["odata-entityid"]?.match(/\(([^)]+)\)/)?.[1],m=a.data,g=x[t]??t.replace(/s$/,"")+"id",f=p??m?.[g]??n;return{operation:o,id:f}}catch(a){if(a instanceof y&&a.status===412){if(r==="createOnly")throw new Error("Record already exists");if(r==="updateOnly")throw new Error("Record not found")}throw a}})}async associate(t,e,n,s,r){let i=`${this.authProvider.environmentUrl}/api/data/v${P}/${s}(${r})`;await this.requestWithRetry(()=>this.http.post(`${t}(${e})/${n}/$ref`,{"@odata.id":i}))}async disassociate(t,e,n,s,r){let i=s?`?$id=${this.authProvider.environmentUrl}/api/data/v${P}/${r??t}(${s})`:"";await this.requestWithRetry(()=>this.http.delete(`${t}(${e})/${n}/$ref${i}`))}};var w=class extends ${async executeAction(t,e={}){return this.requestWithRetry(()=>this.http.post(t,e).then(n=>n.data))}async executeFunction(t,e={}){let n=[],s=[],r=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;Object.entries(e).forEach(([u,a])=>{if(typeof a=="object"&&a!==null){let o=`@${u}`;s.push(`${l(u)}=${o}`),n.push(`${o}=${encodeURIComponent(JSON.stringify(a))}`)}else typeof a=="string"&&r.test(a)?s.push(`${l(u)}=${a}`):typeof a=="string"?s.push(`${l(u)}='${l(a)}'`):s.push(`${l(u)}=${String(a)}`)});let i=s.length?`${t}(${s.join(",")})`:`${t}()`,c=n.length?`${i}?${n.join("&")}`:i;return this.requestWithRetry(()=>this.http.get(c).then(u=>u.data))}async search(t){let n=`${this.http.baseURL.replace(/\/api\/data\/v[\d.]+\/?$/,"")}/api/search/v2.0/query`;return this.requestWithRetry(()=>this.http.post(n,t).then(s=>s.data))}async executeBoundAction(t,e,n,s={}){return this.requestWithRetry(()=>this.http.post(`${t}(${e})/Microsoft.Dynamics.CRM.${n}`,s).then(r=>r.data))}};var b=class extends w{async listDependencies(t,e){return this.requestWithRetry(()=>this.http.get(`RetrieveDependenciesForDelete(ComponentType=${t},ObjectId=${e})`).then(n=>n.data.value))}async listTableDependencies(t,e){let n={0:"Workflow",1:"Dialog",2:"BusinessRule",3:"Action",4:"BusinessProcessFlow",5:"Flow"},s={0:"Draft",1:"Active",2:"Inactive"},i=(await this.requestWithRetry(()=>this.http.get(`workflows?$filter=primaryentity eq '${l(t)}' and statecode ne 2&$select=name,workflowid,statecode,category,triggeroncreate,triggerondelete,triggeronupdateattributelist`).then(o=>o.data))).value.map(o=>{let d=[];return o.triggeroncreate&&d.push("Create"),o.triggerondelete&&d.push("Delete"),o.triggeronupdateattributelist&&d.push("Update"),{componentType:n[o.category]??`Category${o.category}`,name:o.name,id:o.workflowid,state:s[o.statecode]??`State${o.statecode}`,triggerEvent:d.length?d.join(","):null,solutionName:null}}),c=e?.length?i.filter(o=>e.includes(o.componentType)):i,a=e?.some(o=>o==="Plugin"||o==="CustomAPI")?"Plugin and CustomAPI types require additional SDK message queries and are not yet implemented. Results show Workflow/BusinessRule/Flow/Action dependencies only.":null;return{tableName:t,dependencies:c,count:c.length,warning:a}}async listGlobalOptionSets(){return this.requestWithRetry(()=>this.http.get("GlobalOptionSetDefinitions").then(t=>t.data.value))}async getOptionSet(t){return this.requestWithRetry(()=>this.http.get(`GlobalOptionSetDefinitions(Name='${l(t)}')`).then(e=>e.data))}async getAttributeOptionSet(t,e){let n=["PicklistAttributeMetadata","MultiSelectPicklistAttributeMetadata","StatusAttributeMetadata","StateAttributeMetadata"];for(let s of n)try{let r=`EntityDefinitions(LogicalName='${l(t)}')/Attributes(LogicalName='${l(e)}')/Microsoft.Dynamics.CRM.${s}?$select=LogicalName,DisplayName&$expand=OptionSet`,a=((await this.requestWithRetry(()=>this.http.get(r).then(o=>o.data))).OptionSet?.Options??[]).map(o=>({label:o.Label?.UserLocalizedLabel?.Label??"",value:o.Value}));return{entityLogicalName:t,attributeLogicalName:e,attributeType:s.replace("AttributeMetadata",""),options:a}}catch{continue}throw new Error(`Attribute '${e}' on entity '${t}' is not a Picklist, MultiSelectPicklist, Status, or State attribute, or does not exist.`)}async getEntityKeys(t){return this.requestWithRetry(async()=>(await this.http.get(`EntityDefinitions(LogicalName='${l(t)}')/Keys?$select=SchemaName,LogicalName,KeyAttributes,IsCustomizable,EntityKeyIndexStatus`)).data.value.map(n=>({schemaName:n.SchemaName,logicalName:n.LogicalName,keyAttributes:n.KeyAttributes,isCustomizable:n.IsCustomizable?.Value??!1,indexStatus:n.EntityKeyIndexStatus})))}async updateEntityDefinition(t,e){await this.requestWithRetry(()=>this.http.patch(`EntityDefinitions(LogicalName='${l(t)}')`,e,{headers:{"MSCRM.MergeLabels":"true"}}))}async createAttribute(t,e){return this.requestWithRetry(async()=>(await this.http.post(`EntityDefinitions(LogicalName='${l(t)}')/Attributes`,e,{headers:{Prefer:"return=representation"}})).data.MetadataId??"")}async updateAttribute(t,e,n){await this.requestWithRetry(()=>this.http.put(`EntityDefinitions(LogicalName='${l(t)}')/Attributes(LogicalName='${l(e)}')`,n,{headers:{"MSCRM.MergeLabels":"true"}}))}async deleteAttribute(t,e){await this.requestWithRetry(()=>this.http.delete(`EntityDefinitions(LogicalName='${l(t)}')/Attributes(LogicalName='${l(e)}')`))}async createRelationship(t){return this.requestWithRetry(async()=>(await this.http.post("RelationshipDefinitions",t)).headers["odata-entityid"]?.match(/\(([^)]+)\)$/)?.[1]??"")}};var T=class extends b{async batchExecute(t,e=!1){let n=`batch_${Date.now()}`,s="";if(e){let i=`changeset_${Date.now()+1}`,c=t.filter(a=>a.method==="GET"),u=t.filter(a=>a.method!=="GET");for(let a of c)s+=`--${n}\r
|
|
6
|
+
`,s+=`Content-Type: application/http\r
|
|
7
|
+
`,s+=`Content-Transfer-Encoding: binary\r
|
|
8
|
+
\r
|
|
9
|
+
`,s+=`${a.method} ${this.http.baseURL}${a.url} HTTP/1.1\r
|
|
10
|
+
`,s+=`Accept: application/json\r
|
|
11
|
+
\r
|
|
12
|
+
`;if(u.length>0){s+=`--${n}\r
|
|
13
|
+
`,s+=`Content-Type: multipart/mixed; boundary=${i}\r
|
|
14
|
+
\r
|
|
15
|
+
`;let a=1;for(let o of u)s+=`--${i}\r
|
|
16
|
+
`,s+=`Content-Type: application/http\r
|
|
17
|
+
`,s+=`Content-Transfer-Encoding: binary\r
|
|
18
|
+
`,s+=`Content-ID: ${o.contentId??a++}\r
|
|
19
|
+
\r
|
|
20
|
+
`,s+=`${o.method} ${this.http.baseURL}${o.url} HTTP/1.1\r
|
|
21
|
+
`,s+=`Content-Type: application/json\r
|
|
22
|
+
\r
|
|
23
|
+
`,o.body&&(s+=JSON.stringify(o.body)),s+=`\r
|
|
24
|
+
`;s+=`--${i}--\r
|
|
25
|
+
`}}else t.forEach(i=>{s+=`--${n}\r
|
|
26
|
+
`,s+=`Content-Type: application/http\r
|
|
27
|
+
`,s+=`Content-Transfer-Encoding: binary\r
|
|
28
|
+
\r
|
|
29
|
+
`,s+=`${i.method} ${this.http.baseURL}${i.url} HTTP/1.1\r
|
|
30
|
+
`,s+=`Content-Type: application/json\r
|
|
31
|
+
\r
|
|
32
|
+
`,i.body&&(s+=JSON.stringify(i.body)),s+=`\r
|
|
33
|
+
`});s+=`--${n}--`;let r=await this.requestWithRetry(()=>this.http.post("$batch",s,{headers:{"Content-Type":`multipart/mixed;boundary=${n}`},responseType:"text"}));try{let c=(r.headers["content-type"]??"").match(/boundary=(?:"([^"]+)"|([^;"\s]+))/),u=c?.[1]??c?.[2];return u?v(r.data,u):(process.stderr.write(`[batchExecute] No multipart boundary in response Content-Type; returning raw data.
|
|
34
|
+
`),[r.data])}catch(i){return process.stderr.write(`[batchExecute] Failed to parse multipart response; returning raw data. ${String(i)}
|
|
35
|
+
`),[r.data]}}};var E={1:"Entity",2:"Attribute",3:"Relationship",9:"OptionSet",29:"Workflow",61:"SystemForm",71:"SiteMap",90:"PluginAssembly",92:"PluginType",97:"WebResource",95:"ServiceEndpoint",79:"ConnectionRole"};function k(h){return h.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}var q=class extends T{async executeBoundFunction(t,e,n,s={}){let r=[],i=[];Object.entries(s).forEach(([o,d])=>{if(typeof d=="object"&&d!==null){let p=`@${o}`;i.push(`${l(o)}=${p}`),r.push(`${p}=${encodeURIComponent(JSON.stringify(d))}`)}else typeof d=="string"?i.push(`${l(o)}='${l(d)}'`):i.push(`${l(o)}=${String(d)}`)});let c=i.join(","),u=`${t}(${e})/Microsoft.Dynamics.CRM.${n}(${c})`,a=r.length?`${u}?${r.join("&")}`:u;return this.requestWithRetry(()=>this.http.get(a).then(o=>o.data))}async queryWithPaging(t,e={}){let n=Math.min(e.maxTotal??5e3,5e4),s=[],r=0,i={};e.select!==void 0&&(i.select=e.select),e.filter!==void 0&&(i.filter=e.filter),e.orderby!==void 0&&(i.orderby=e.orderby),e.expand!==void 0&&(i.expand=e.expand);let c=await this.query(t,i);for(s.push(...c.value),r++;c["@odata.nextLink"]&&s.length<n;){let a=c["@odata.nextLink"];c=await this.requestWithRetry(()=>this.http.get(a).then(o=>o.data)),s.push(...c.value),r++}let u=s.slice(0,n);return{records:u,totalRetrieved:u.length,pageCount:r}}async getChangedRecords(t,e,n){let s,r={};if(e===null){let p=n?.length?`?$select=${n.join(",")}`:"";s=`${t}${p}`,r.Prefer="odata.track-changes"}else{let p=n?.length?`&$select=${n.join(",")}`:"";s=`${t}?$deltatoken=${e}${p}`}let i=await this.requestWithRetry(()=>this.http.get(s,{headers:r}).then(p=>p.data)),c=i.value??[],u=[],a=[];for(let p of c)if("@removed"in p){let m=String(p["@id"]??""),g=m.match(/\(([^)]+)\)$/);a.push({id:g?g[1]:m})}else u.push(p);let o=i["@odata.deltaLink"],d=null;if(o){let p=o.match(/\$deltatoken=([^&]+)/);d=p?decodeURIComponent(p[1]):null}return{newAndModified:u,deleted:a,nextDeltaToken:d}}async getSolutionComponents(t,e,n=200){return this.requestWithRetry(async()=>{let r=(await this.http.get(`solutions?$filter=uniquename eq '${l(t)}'&$select=solutionid,uniquename,friendlyname,version&$top=1`)).data.value;if(!r.length)throw new Error(`Solution '${t}' not found`);let i=r[0],c=i.solutionid,u=`_solutionid_value eq ${c}`;e!==void 0&&(u+=` and componenttype eq ${e}`);let o=(await this.http.get(`solutioncomponents?$filter=${u}&$select=componenttype,objectid&$top=${n}&$orderby=componenttype`)).data.value.map(d=>({componentType:d.componenttype,componentTypeName:E[d.componenttype]??`Type${d.componenttype}`,objectId:d.objectid}));return{solutionName:i.uniquename,solutionId:c,friendlyName:i.friendlyname,version:i.version,components:o,count:o.length}})}async publishCustomizations(t){return this.requestWithRetry(async()=>{if(!(t&&((t.entities?.length??0)>0||(t.webResources?.length??0)>0||(t.optionSets?.length??0)>0)))return await this.http.post("PublishAllXml",{},{timeoutMs:12e4}),{published:!0,message:"All customizations published successfully"};let n="<importexportxml>";return t.entities?.length&&(n+="<entities>"+t.entities.map(s=>`<entity>${k(s)}</entity>`).join("")+"</entities>"),t.webResources?.length&&(n+="<webresources>"+t.webResources.map(s=>`<webresource>${k(s)}</webresource>`).join("")+"</webresources>"),t.optionSets?.length&&(n+="<optionsets>"+t.optionSets.map(s=>`<optionset>${k(s)}</optionset>`).join("")+"</optionsets>"),n+="</importexportxml>",await this.http.post("PublishXml",{ParameterXml:n},{timeoutMs:12e4}),{published:!0,message:"Selected customizations published successfully"}})}async listDataverseWorkflows(t){return this.requestWithRetry(async()=>{let e=[];t.category!==void 0&&e.push(`category eq ${t.category}`),t.nameContains&&e.push(`contains(name,'${l(t.nameContains)}')`);let n=`workflows?$select=workflowid,name,description,category,statecode,statuscode,type,modifiedon&$orderby=name asc&$top=${t.top??50}`;return e.length>0&&(n+=`&$filter=${e.join(" and ")}`),(await this.http.get(n)).data.value??[]})}async getDataverseWorkflow(t){return this.requestWithRetry(()=>this.http.get(`workflows(${t})?$select=workflowid,name,description,category,statecode,statuscode,type,modifiedon`).then(e=>e.data))}async executeFetchXmlAllPages(t,e){let n=[],s=1,r;do{let i=e;s>1&&(i=i.replace(/<fetch\b([^>]*)>/i,(o,d)=>{let p=d.replace(/\s+page="[^"]*"/g,"").replace(/\s+paging-cookie="[^"]*"/g,""),m=r?` paging-cookie="${r.replace(/"/g,""").replace(/'/g,"'")}"`:"";return`<fetch${p} page="${s}"${m}>`}));let c=await this.executeFetchXml(t,i),u=c.value??[];n.push(...u);let a=c["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"];if(!a||u.length===0)break;try{let d=decodeURIComponent(decodeURIComponent(String(a))).match(/pagingcookie="([^"]+)"/);r=d?d[1]:void 0}catch{r=String(a)}if(!r||(s++,s>100))break}while(!0);return n}};export{l as a,q as b};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as a}from"./chunk-FSM3J3WD.js";export{a as DataverseAdvancedClient};
|
package/dist/doctor.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
async function f(){let t=e=>process.stdout.write(e+`
|
|
3
|
-
`),o=e=>t(` \u2705 ${e}`),n=e=>t(` \u274C ${e}`);t(""),t("\u{1F3E5} mcp-dataverse doctor"),t("\u2500".repeat(50)),t("");let r=!0;t("\u{1F4CB} Environment");let c=process.version;parseInt(c.slice(1).split(".")[0],10)>=20?o(`Node.js ${c}`):(n(`Node.js ${c} \u2014 requires v20+`),r=!1),t(""),t("\u2699\uFE0F Configuration");try{let{loadConfig:e}=await import("./config.loader-VTIKUDN7.js"),s=e();o(`Environment URL: ${s.environmentUrl}`),o(`Timeout: ${s.requestTimeoutMs}ms, Retries: ${s.maxRetries}`)}catch(e){let s=e instanceof Error?e.message:String(e);n(`Configuration error: ${s}`),r=!1,t(""),t(r?"\u2705 All checks passed!":"\u274C Some checks failed."),process.exit(r?0:1)}t(""),t("\u{1F511} Authentication");try{let{loadConfig:e}=await import("./config.loader-VTIKUDN7.js"),s=e(),{createAuthProvider:l}=await import("./auth-provider.factory-MSMLSOX3.js"),i=await l(s).getToken();i?(o("Token acquired successfully"),i.split(".").length===3&&o("Valid JWT token format")):(n("No token returned"),r=!1)}catch(e){let s=e instanceof Error?e.message:String(e);n(`Auth failed: ${s}`),r=!1}t(""),t("\u{1F310} Dataverse API");try{let{loadConfig:e}=await import("./config.loader-VTIKUDN7.js"),s=e(),{createAuthProvider:l}=await import("./auth-provider.factory-MSMLSOX3.js"),{DataverseAdvancedClient:m}=await import("./dataverse-client-advanced-
|
|
3
|
+
`),o=e=>t(` \u2705 ${e}`),n=e=>t(` \u274C ${e}`);t(""),t("\u{1F3E5} mcp-dataverse doctor"),t("\u2500".repeat(50)),t("");let r=!0;t("\u{1F4CB} Environment");let c=process.version;parseInt(c.slice(1).split(".")[0],10)>=20?o(`Node.js ${c}`):(n(`Node.js ${c} \u2014 requires v20+`),r=!1),t(""),t("\u2699\uFE0F Configuration");try{let{loadConfig:e}=await import("./config.loader-VTIKUDN7.js"),s=e();o(`Environment URL: ${s.environmentUrl}`),o(`Timeout: ${s.requestTimeoutMs}ms, Retries: ${s.maxRetries}`)}catch(e){let s=e instanceof Error?e.message:String(e);n(`Configuration error: ${s}`),r=!1,t(""),t(r?"\u2705 All checks passed!":"\u274C Some checks failed."),process.exit(r?0:1)}t(""),t("\u{1F511} Authentication");try{let{loadConfig:e}=await import("./config.loader-VTIKUDN7.js"),s=e(),{createAuthProvider:l}=await import("./auth-provider.factory-MSMLSOX3.js"),i=await l(s).getToken();i?(o("Token acquired successfully"),i.split(".").length===3&&o("Valid JWT token format")):(n("No token returned"),r=!1)}catch(e){let s=e instanceof Error?e.message:String(e);n(`Auth failed: ${s}`),r=!1}t(""),t("\u{1F310} Dataverse API");try{let{loadConfig:e}=await import("./config.loader-VTIKUDN7.js"),s=e(),{createAuthProvider:l}=await import("./auth-provider.factory-MSMLSOX3.js"),{DataverseAdvancedClient:m}=await import("./dataverse-client-advanced-EASNSX3M.js"),i=l(s),a=await new m(i,s.maxRetries,s.requestTimeoutMs).whoAmI();o(`Organization: ${a.OrganizationName||"N/A"}`),o(`User ID: ${a.UserId||"N/A"}`),o(`Business Unit: ${a.BusinessUnitId||"N/A"}`),o(`Environment: ${a.EnvironmentUrl||s.environmentUrl}`)}catch(e){let s=e instanceof Error?e.message:String(e);n(`API call failed: ${s}`),r=!1}t(""),t("\u2500".repeat(50)),t(r?"\u2705 All checks passed! Your mcp-dataverse setup is healthy.":"\u274C Some checks failed. Review the errors above."),t(""),process.exit(r?0:1)}export{f as runDoctor};
|