powerplatform-mcp 0.4.5 → 1.0.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.
- package/README.md +38 -49
- package/build/PowerPlatformClient.js +83 -0
- package/build/PowerPlatformService.js +2 -32
- package/build/index.js +46 -657
- package/build/models/ApiCollectionResponse.js +1 -0
- package/build/models/index.js +1 -0
- package/build/prompts/entityPrompts.js +244 -0
- package/build/prompts/index.js +9 -0
- package/build/prompts/templates.js +34 -0
- package/build/services/EntityService.js +128 -0
- package/build/services/OptionSetService.js +18 -0
- package/build/services/PluginService.js +288 -0
- package/build/services/RecordService.js +29 -0
- package/build/services/index.js +4 -0
- package/build/tools/entityTools.js +156 -0
- package/build/tools/index.js +17 -0
- package/build/tools/optionSetTools.js +43 -0
- package/build/tools/pluginTools.js +188 -0
- package/build/tools/recordTools.js +87 -0
- package/build/types.js +1 -0
- package/package.json +12 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PowerPlatform MCP Server
|
|
2
2
|
|
|
3
|
-
A Model Context Protocol (MCP) server that provides intelligent access to PowerPlatform/Dataverse entities and records. This tool offers
|
|
3
|
+
A Model Context Protocol (MCP) server that provides intelligent access to PowerPlatform/Dataverse entities and records. This tool offers context-aware assistance, entity exploration and metadata access.
|
|
4
4
|
|
|
5
5
|
Key features:
|
|
6
6
|
- Rich entity metadata exploration with formatted, context-aware prompts
|
|
@@ -9,8 +9,6 @@ Key features:
|
|
|
9
9
|
- AI-assisted query building and data modeling through AI agent
|
|
10
10
|
- Full access to entity attributes, relationships, and global option sets
|
|
11
11
|
|
|
12
|
-
Perfect for developers working with PowerPlatform/Dataverse who want intelligent, context-aware assistance for entity exploration and data querying.
|
|
13
|
-
|
|
14
12
|
## Installation
|
|
15
13
|
|
|
16
14
|
You can install and run this tool in two ways:
|
|
@@ -47,9 +45,29 @@ POWERPLATFORM_CLIENT_SECRET=your-azure-app-client-secret
|
|
|
47
45
|
POWERPLATFORM_TENANT_ID=your-azure-tenant-id
|
|
48
46
|
```
|
|
49
47
|
|
|
48
|
+
### For Development
|
|
49
|
+
|
|
50
|
+
1. Clone the repository and install dependencies:
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/michsob/powerplatform-mcp.git
|
|
53
|
+
cd powerplatform-mcp
|
|
54
|
+
npm install
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
2. Copy `.env.example` to `.env` and fill in your credentials:
|
|
58
|
+
```bash
|
|
59
|
+
cp .env.example .env
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
3. Build and test:
|
|
63
|
+
```bash
|
|
64
|
+
npm run build
|
|
65
|
+
npm run inspector:debug
|
|
66
|
+
```
|
|
67
|
+
|
|
50
68
|
## Usage
|
|
51
69
|
|
|
52
|
-
This is an MCP server designed to work with MCP-compatible clients like GitHub Copilot. Once running, it will expose tools for retrieving PowerPlatform entity metadata.
|
|
70
|
+
This is an MCP server designed to work with MCP-compatible clients like Cursor, Claude App and GitHub Copilot. Once running, it will expose tools for retrieving PowerPlatform entity metadata and records.
|
|
53
71
|
|
|
54
72
|
### Available Tools
|
|
55
73
|
|
|
@@ -64,7 +82,7 @@ This is an MCP server designed to work with MCP-compatible clients like GitHub C
|
|
|
64
82
|
|
|
65
83
|
## MCP Prompts
|
|
66
84
|
|
|
67
|
-
The server includes a prompts feature that provides formatted, context-rich information about PowerPlatform entities.
|
|
85
|
+
The server includes a prompts feature that provides formatted, context-rich information about PowerPlatform entities.
|
|
68
86
|
|
|
69
87
|
### Available Prompt Types
|
|
70
88
|
|
|
@@ -205,22 +223,18 @@ This shows all relationships for the 'contact' entity:
|
|
|
205
223
|
- contactquotes_association: contact (N) ↔ quote (N)
|
|
206
224
|
```
|
|
207
225
|
|
|
208
|
-
##
|
|
209
|
-
|
|
210
|
-
These prompts are particularly valuable when used with AI assistants like GitHub Copilot that can integrate with MCP.
|
|
211
|
-
|
|
212
|
-
### GitHub Copilot Examples
|
|
226
|
+
## Prompt Examples
|
|
213
227
|
|
|
214
|
-
Here are some examples of how you can interact with
|
|
228
|
+
Here are some examples of how you can interact with assistant using the PowerPlatform MCP prompts:
|
|
215
229
|
|
|
216
|
-
|
|
230
|
+
### 1. Entity Understanding
|
|
217
231
|
|
|
218
|
-
You can ask
|
|
232
|
+
You can ask assistant about entities in natural language:
|
|
219
233
|
|
|
220
234
|
```
|
|
221
235
|
User: "Tell me about the Account entity in our PowerPlatform environment"
|
|
222
236
|
|
|
223
|
-
|
|
237
|
+
Response:
|
|
224
238
|
[uses ENTITY_OVERVIEW prompt internally]
|
|
225
239
|
|
|
226
240
|
Here's what I found about the Account entity:
|
|
@@ -234,14 +248,14 @@ Here's what I found about the Account entity:
|
|
|
234
248
|
- It has 42 one-to-many relationships and 8 many-to-many relationships
|
|
235
249
|
```
|
|
236
250
|
|
|
237
|
-
|
|
251
|
+
### 2. Building Queries
|
|
238
252
|
|
|
239
253
|
You can ask for help constructing queries:
|
|
240
254
|
|
|
241
255
|
```
|
|
242
256
|
User: "Help me write a query to find active accounts with revenue over $1M in California"
|
|
243
257
|
|
|
244
|
-
|
|
258
|
+
Response:
|
|
245
259
|
[uses QUERY_TEMPLATE prompt internally]
|
|
246
260
|
|
|
247
261
|
Here's the OData query you need:
|
|
@@ -259,14 +273,14 @@ This query:
|
|
|
259
273
|
5. Orders by revenue highest to lowest
|
|
260
274
|
```
|
|
261
275
|
|
|
262
|
-
|
|
276
|
+
### 3. Understanding Relationships
|
|
263
277
|
|
|
264
278
|
You can explore entity relationships naturally:
|
|
265
279
|
|
|
266
280
|
```
|
|
267
281
|
User: "How are Accounts and Contacts related in our system?"
|
|
268
282
|
|
|
269
|
-
|
|
283
|
+
Response:
|
|
270
284
|
[uses RELATIONSHIP_MAP prompt for both entities internally]
|
|
271
285
|
|
|
272
286
|
Here are the key relationships between Accounts and Contacts:
|
|
@@ -284,14 +298,14 @@ Here are the key relationships between Accounts and Contacts:
|
|
|
284
298
|
- account_connections: For relationship management
|
|
285
299
|
```
|
|
286
300
|
|
|
287
|
-
|
|
301
|
+
### 4. Field/Attribute Investigation
|
|
288
302
|
|
|
289
303
|
You can ask about specific fields:
|
|
290
304
|
|
|
291
305
|
```
|
|
292
306
|
User: "What kind of field is the revenue field on Account?"
|
|
293
307
|
|
|
294
|
-
|
|
308
|
+
Response:
|
|
295
309
|
[uses ATTRIBUTE_DETAILS prompt internally]
|
|
296
310
|
|
|
297
311
|
The revenue field on Account is:
|
|
@@ -303,14 +317,14 @@ The revenue field on Account is:
|
|
|
303
317
|
- Can be used in advanced find and filtered views
|
|
304
318
|
```
|
|
305
319
|
|
|
306
|
-
|
|
320
|
+
### 5. Complex Data Modeling
|
|
307
321
|
|
|
308
322
|
You can get help with data modeling decisions:
|
|
309
323
|
|
|
310
324
|
```
|
|
311
325
|
User: "I need to design a solution for tracking product reviews. Which entities should I relate to?"
|
|
312
326
|
|
|
313
|
-
|
|
327
|
+
Response:
|
|
314
328
|
[uses multiple ENTITY_OVERVIEW and RELATIONSHIP_MAP prompts internally]
|
|
315
329
|
|
|
316
330
|
Based on the existing data model, here's a suggested approach:
|
|
@@ -326,36 +340,11 @@ Based on the existing data model, here's a suggested approach:
|
|
|
326
340
|
- Contact (N:1) - Reviews are written by contacts
|
|
327
341
|
- Account (N:1) - Optional link to company if B2B review
|
|
328
342
|
|
|
329
|
-
Here's a sample lookup field structure...
|
|
330
|
-
[continues with detailed implementation guidance]
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
#### 6. Debugging Assistance
|
|
334
343
|
|
|
335
|
-
You can get help troubleshooting:
|
|
336
|
-
|
|
337
|
-
```
|
|
338
|
-
User: "Why am I getting 'invalid property' when querying account.customertypecode?"
|
|
339
344
|
|
|
340
|
-
GitHub Copilot: Let me check the attribute details...
|
|
341
|
-
[uses ATTRIBUTE_DETAILS prompt internally]
|
|
342
|
-
|
|
343
|
-
I see the issue. The field 'customertypecode' is actually named 'customertype' in your environment. Here's the correct field information:
|
|
344
|
-
- Logical Name: customertype
|
|
345
|
-
- Type: OptionSetValue
|
|
346
|
-
- Valid Values:
|
|
347
|
-
* 1 = Competitor
|
|
348
|
-
* 2 = Consultant
|
|
349
|
-
* 3 = Customer
|
|
350
|
-
* 4 = Investor
|
|
351
|
-
* 5 = Partner
|
|
352
|
-
* 6 = Influencer
|
|
353
|
-
|
|
354
|
-
Try updating your query to use 'customertype' instead of 'customertypecode'.
|
|
355
|
-
```
|
|
356
345
|
|
|
357
|
-
These examples show how
|
|
346
|
+
These examples show how AI assistant can leverage the MCP prompts to provide context-aware, accurate assistance for PowerPlatform development tasks. The AI understands your environment's specific configuration and can help with both simple queries and complex architectural decisions.
|
|
358
347
|
|
|
359
348
|
## License
|
|
360
349
|
|
|
361
|
-
MIT
|
|
350
|
+
MIT
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { ConfidentialClientApplication } from '@azure/msal-node';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
/**
|
|
4
|
+
* Base client for PowerPlatform API access.
|
|
5
|
+
* Handles authentication and generic HTTP requests.
|
|
6
|
+
* Service classes should depend on this client via constructor injection.
|
|
7
|
+
*/
|
|
8
|
+
export class PowerPlatformClient {
|
|
9
|
+
config;
|
|
10
|
+
msalClient;
|
|
11
|
+
accessToken = null;
|
|
12
|
+
tokenExpirationTime = 0;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
// Initialize MSAL client
|
|
16
|
+
this.msalClient = new ConfidentialClientApplication({
|
|
17
|
+
auth: {
|
|
18
|
+
clientId: this.config.clientId,
|
|
19
|
+
clientSecret: this.config.clientSecret,
|
|
20
|
+
authority: `https://login.microsoftonline.com/${this.config.tenantId}`,
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get the organization URL
|
|
26
|
+
*/
|
|
27
|
+
get organizationUrl() {
|
|
28
|
+
return this.config.organizationUrl;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get an access token for the PowerPlatform API
|
|
32
|
+
*/
|
|
33
|
+
async getAccessToken() {
|
|
34
|
+
const currentTime = Date.now();
|
|
35
|
+
// If we have a token that isn't expired, return it
|
|
36
|
+
if (this.accessToken && this.tokenExpirationTime > currentTime) {
|
|
37
|
+
return this.accessToken;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
// Get a new token
|
|
41
|
+
const result = await this.msalClient.acquireTokenByClientCredential({
|
|
42
|
+
scopes: [`${this.config.organizationUrl}/.default`],
|
|
43
|
+
});
|
|
44
|
+
if (!result || !result.accessToken) {
|
|
45
|
+
throw new Error('Failed to acquire access token');
|
|
46
|
+
}
|
|
47
|
+
this.accessToken = result.accessToken;
|
|
48
|
+
// Set expiration time (subtract 5 minutes to refresh early)
|
|
49
|
+
if (result.expiresOn) {
|
|
50
|
+
this.tokenExpirationTime = result.expiresOn.getTime() - (5 * 60 * 1000);
|
|
51
|
+
}
|
|
52
|
+
return this.accessToken;
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error('Error acquiring access token:', error);
|
|
56
|
+
throw new Error('Authentication failed');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Make an authenticated GET request to the PowerPlatform API
|
|
61
|
+
* @param endpoint The API endpoint (relative to organization URL)
|
|
62
|
+
*/
|
|
63
|
+
async get(endpoint) {
|
|
64
|
+
try {
|
|
65
|
+
const token = await this.getAccessToken();
|
|
66
|
+
const response = await axios({
|
|
67
|
+
method: 'GET',
|
|
68
|
+
url: `${this.config.organizationUrl}/${endpoint}`,
|
|
69
|
+
headers: {
|
|
70
|
+
'Authorization': `Bearer ${token}`,
|
|
71
|
+
'Accept': 'application/json',
|
|
72
|
+
'OData-MaxVersion': '4.0',
|
|
73
|
+
'OData-Version': '4.0'
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return response.data;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error('PowerPlatform API request failed:', error);
|
|
80
|
+
throw new Error(`PowerPlatform API request failed: ${error}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -45,28 +45,6 @@ export class PowerPlatformService {
|
|
|
45
45
|
throw new Error('Authentication failed');
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Handle JSON-RPC error response
|
|
50
|
-
* @param error JSON-RPC error object
|
|
51
|
-
* @returns Formatted error information
|
|
52
|
-
*/
|
|
53
|
-
handleJsonRpcError(error) {
|
|
54
|
-
// Log the error for debugging
|
|
55
|
-
console.error('JSON-RPC error:', error);
|
|
56
|
-
// Handle specific error codes
|
|
57
|
-
switch (error.code) {
|
|
58
|
-
case -32601:
|
|
59
|
-
return `Method not found: ${error.message}. Please check that you're calling a supported API method.`;
|
|
60
|
-
case -32602:
|
|
61
|
-
return `Invalid params: ${error.message}. Please check your request parameters.`;
|
|
62
|
-
case -32603:
|
|
63
|
-
return `Internal error: ${error.message}. Please try again later.`;
|
|
64
|
-
case -32000:
|
|
65
|
-
return `Server error: ${error.message}. Please check server logs for more details.`;
|
|
66
|
-
default:
|
|
67
|
-
return `RPC error ${error.code}: ${error.message}`;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
48
|
/**
|
|
71
49
|
* Make an authenticated request to the PowerPlatform API
|
|
72
50
|
*/
|
|
@@ -86,16 +64,8 @@ export class PowerPlatformService {
|
|
|
86
64
|
return response.data;
|
|
87
65
|
}
|
|
88
66
|
catch (error) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const jsonRpcError = error.response.data.error;
|
|
92
|
-
const errorMessage = this.handleJsonRpcError(jsonRpcError);
|
|
93
|
-
throw new Error(errorMessage);
|
|
94
|
-
}
|
|
95
|
-
// For any other type of error, convert to string safely
|
|
96
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
97
|
-
console.error('PowerPlatform API request failed:', errorMessage);
|
|
98
|
-
throw new Error(`PowerPlatform API request failed: ${errorMessage}`);
|
|
67
|
+
console.error('PowerPlatform API request failed:', error);
|
|
68
|
+
throw new Error(`PowerPlatform API request failed: ${error}`);
|
|
99
69
|
}
|
|
100
70
|
}
|
|
101
71
|
/**
|