mcp-consultant-tools 0.4.6 → 2.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 +98 -138
- package/build/index.js +5 -150
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,41 @@ npx mcp-consultant-tools
|
|
|
37
37
|
|
|
38
38
|
This is an MCP server designed to work with MCP-compatible clients like Claude Desktop, Cursor, or Claude Code (VS Code extension).
|
|
39
39
|
|
|
40
|
+
### Quick Start: VS Code (Claude Code) Configuration
|
|
41
|
+
|
|
42
|
+
For VS Code with Claude Code extension, create a `.vscode/mcp.json` file in your repository:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"servers": {
|
|
47
|
+
"mcp-consultant-tools": {
|
|
48
|
+
"command": "npx",
|
|
49
|
+
"args": ["-y", "mcp-consultant-tools"],
|
|
50
|
+
"env": {
|
|
51
|
+
"POWERPLATFORM_URL": "https://yourenvironment.crm.dynamics.com",
|
|
52
|
+
"POWERPLATFORM_CLIENT_ID": "your-azure-app-client-id",
|
|
53
|
+
"POWERPLATFORM_CLIENT_SECRET": "your-azure-app-client-secret",
|
|
54
|
+
"POWERPLATFORM_TENANT_ID": "your-azure-tenant-id",
|
|
55
|
+
"AZUREDEVOPS_ORGANIZATION": "your-organization-name",
|
|
56
|
+
"AZUREDEVOPS_PAT": "your-personal-access-token",
|
|
57
|
+
"AZUREDEVOPS_PROJECTS": "Project1,Project2",
|
|
58
|
+
"AZUREDEVOPS_API_VERSION": "7.1",
|
|
59
|
+
"AZUREDEVOPS_ENABLE_WORK_ITEM_WRITE": "true",
|
|
60
|
+
"AZUREDEVOPS_ENABLE_WORK_ITEM_DELETE": "false",
|
|
61
|
+
"AZUREDEVOPS_ENABLE_WIKI_WRITE": "false"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**After configuration:**
|
|
69
|
+
1. Save the `.vscode/mcp.json` file
|
|
70
|
+
2. Reload VS Code window
|
|
71
|
+
3. The MCP server will be available in Claude Code
|
|
72
|
+
|
|
73
|
+
**Note:** You can omit PowerPlatform or Azure DevOps credentials if you only need one integration (see Environment Variables Reference below).
|
|
74
|
+
|
|
40
75
|
### Quick Start: Claude Desktop Configuration
|
|
41
76
|
|
|
42
77
|
Add this to your Claude Desktop config file at `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
@@ -97,7 +132,12 @@ For local development and testing, you can run the server directly from your clo
|
|
|
97
132
|
|
|
98
133
|
### Environment Variables Reference
|
|
99
134
|
|
|
100
|
-
**PowerPlatform
|
|
135
|
+
**Note:** Both PowerPlatform and Azure DevOps integrations are optional. You can configure only the services you need:
|
|
136
|
+
- PowerPlatform only: Set `POWERPLATFORM_*` variables
|
|
137
|
+
- Azure DevOps only: Set `AZUREDEVOPS_*` variables
|
|
138
|
+
- Both: Set all variables
|
|
139
|
+
|
|
140
|
+
**PowerPlatform/Dataverse (Optional):**
|
|
101
141
|
- `POWERPLATFORM_URL`: Your PowerPlatform environment URL
|
|
102
142
|
- `POWERPLATFORM_CLIENT_ID`: Azure AD app registration client ID
|
|
103
143
|
- `POWERPLATFORM_CLIENT_SECRET`: Azure AD app registration client secret
|
|
@@ -131,7 +171,6 @@ Once configured, the MCP server will expose tools for retrieving PowerPlatform e
|
|
|
131
171
|
- `get-global-option-set`: Get a global option set definition
|
|
132
172
|
- `get-record`: Get a specific record by entity name and ID
|
|
133
173
|
- `query-records`: Query records using an OData filter expression
|
|
134
|
-
- `use-powerplatform-prompt`: Use pre-defined prompt templates for PowerPlatform entities
|
|
135
174
|
|
|
136
175
|
#### Plugin Registration & Validation Tools
|
|
137
176
|
- `get-plugin-assemblies`: List all plugin assemblies in the environment
|
|
@@ -141,151 +180,29 @@ Once configured, the MCP server will expose tools for retrieving PowerPlatform e
|
|
|
141
180
|
|
|
142
181
|
## MCP Prompts
|
|
143
182
|
|
|
144
|
-
The server includes
|
|
183
|
+
The server includes MCP prompts that provide formatted, context-rich information.
|
|
145
184
|
|
|
146
|
-
### Available
|
|
185
|
+
### Available Prompts
|
|
147
186
|
|
|
148
187
|
#### Entity Prompts
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
3. **QUERY_TEMPLATE**: OData query template for an entity with example filters
|
|
154
|
-
4. **RELATIONSHIP_MAP**: Visual map of entity relationships
|
|
188
|
+
1. **entity-overview**: Comprehensive overview of a PowerPlatform entity
|
|
189
|
+
2. **attribute-details**: Detailed information about a specific entity attribute
|
|
190
|
+
3. **query-template**: OData query template for an entity with example filters
|
|
191
|
+
4. **relationship-map**: Visual map of entity relationships
|
|
155
192
|
|
|
156
193
|
#### Plugin Prompts
|
|
157
194
|
5. **plugin-deployment-report**: Generate a comprehensive deployment report for a plugin assembly with validation warnings
|
|
158
195
|
6. **entity-plugin-pipeline-report**: Generate a visual execution pipeline showing all plugins for an entity in order
|
|
159
196
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
```javascript
|
|
165
|
-
// Example client code
|
|
166
|
-
await mcpClient.invoke("use-powerplatform-prompt", {
|
|
167
|
-
promptType: "ENTITY_OVERVIEW",
|
|
168
|
-
entityName: "account"
|
|
169
|
-
});
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
**Output:**
|
|
173
|
-
```
|
|
174
|
-
## Power Platform Entity: account
|
|
175
|
-
|
|
176
|
-
This is an overview of the 'account' entity in Microsoft Power Platform/Dataverse:
|
|
197
|
+
#### Workflow & Flow Prompts
|
|
198
|
+
7. **flows-report**: Comprehensive report of all Power Automate flows
|
|
199
|
+
8. **workflows-report**: Comprehensive report of all classic Dynamics workflows
|
|
177
200
|
|
|
178
|
-
|
|
179
|
-
-
|
|
180
|
-
-
|
|
181
|
-
-
|
|
182
|
-
-
|
|
183
|
-
- Primary Name: name
|
|
184
|
-
|
|
185
|
-
### Key Attributes
|
|
186
|
-
- name: String (Account Name)
|
|
187
|
-
- emailaddress1: String (Email)
|
|
188
|
-
- telephone1: String (Main Phone)
|
|
189
|
-
- address1_city: String (City)
|
|
190
|
-
- statecode: Status (Status)
|
|
191
|
-
- accountnumber: String (Account Number)
|
|
192
|
-
- industrycode: OptionSetValue (Industry)
|
|
193
|
-
- revenue: Money (Annual Revenue)
|
|
194
|
-
- ownerid: Owner (Owner)
|
|
195
|
-
- createdon: DateTime (Created On)
|
|
196
|
-
|
|
197
|
-
### Relationships
|
|
198
|
-
- One-to-Many Relationships: 42
|
|
199
|
-
- Many-to-Many Relationships: 8
|
|
200
|
-
|
|
201
|
-
You can query this entity using OData filters against the plural name.
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
#### Attribute Details Prompt
|
|
205
|
-
|
|
206
|
-
```javascript
|
|
207
|
-
await mcpClient.invoke("use-powerplatform-prompt", {
|
|
208
|
-
promptType: "ATTRIBUTE_DETAILS",
|
|
209
|
-
entityName: "account",
|
|
210
|
-
attributeName: "revenue"
|
|
211
|
-
});
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
**Output:**
|
|
215
|
-
```
|
|
216
|
-
## Attribute: revenue
|
|
217
|
-
|
|
218
|
-
Details for the 'revenue' attribute of the 'account' entity:
|
|
219
|
-
|
|
220
|
-
- Display Name: Annual Revenue
|
|
221
|
-
- Description: Annual revenue for the account
|
|
222
|
-
- Type: Money
|
|
223
|
-
- Format: Currency
|
|
224
|
-
- Is Required: No
|
|
225
|
-
- Is Searchable: true
|
|
226
|
-
|
|
227
|
-
### Usage Notes
|
|
228
|
-
- Data Type: Money
|
|
229
|
-
- Required: No
|
|
230
|
-
- Max Length: N/A
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
#### Query Template Prompt
|
|
234
|
-
|
|
235
|
-
```javascript
|
|
236
|
-
await mcpClient.invoke("use-powerplatform-prompt", {
|
|
237
|
-
promptType: "QUERY_TEMPLATE",
|
|
238
|
-
entityName: "account"
|
|
239
|
-
});
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
**Output:**
|
|
243
|
-
```
|
|
244
|
-
## OData Query Template for accounts
|
|
245
|
-
|
|
246
|
-
Use this template to build queries against the accounts entity:
|
|
247
|
-
accounts?$select=name,emailaddress1,telephone1, address1_city,statecode&$filter=name eq 'Example'&$orderby=name asc&$top=50
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### Common Filter Examples
|
|
251
|
-
- Equals: `name eq 'Contoso'`
|
|
252
|
-
- Contains: `contains(name, 'Contoso')`
|
|
253
|
-
- Greater than date: `createdon gt 2023-01-01T00:00:00Z`
|
|
254
|
-
- Multiple conditions: `name eq 'Contoso' and statecode eq 0`
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
#### Relationship Map Prompt
|
|
258
|
-
|
|
259
|
-
```javascript
|
|
260
|
-
await mcpClient.invoke("use-powerplatform-prompt", {
|
|
261
|
-
promptType: "RELATIONSHIP_MAP",
|
|
262
|
-
entityName: "contact"
|
|
263
|
-
});
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
**Output:**
|
|
267
|
-
```
|
|
268
|
-
## Relationship Map for contact
|
|
269
|
-
|
|
270
|
-
This shows all relationships for the 'contact' entity:
|
|
271
|
-
|
|
272
|
-
### One-to-Many Relationships (contact as Primary)
|
|
273
|
-
- contact_activity_parties: contact (1) → activityparty (N)
|
|
274
|
-
- contact_connections1: contact (1) → connection (N)
|
|
275
|
-
- contact_connections2: contact (1) → connection (N)
|
|
276
|
-
- contact_customer_contacts: contact (1) → contact (N)
|
|
277
|
-
- contact_master_contact: contact (1) → contact (N)
|
|
278
|
-
|
|
279
|
-
### One-to-Many Relationships (contact as Related)
|
|
280
|
-
- account_primary_contact: account (1) → contact (N)
|
|
281
|
-
- customer_contacts: customer (1) → contact (N)
|
|
282
|
-
- system_user_contacts: systemuser (1) → contact (N)
|
|
283
|
-
|
|
284
|
-
### Many-to-Many Relationships
|
|
285
|
-
- contactleads_association: contact (N) ↔ lead (N)
|
|
286
|
-
- contactopportunities_association: contact (N) ↔ opportunity (N)
|
|
287
|
-
- contactquotes_association: contact (N) ↔ quote (N)
|
|
288
|
-
```
|
|
201
|
+
#### Azure DevOps Prompts
|
|
202
|
+
9. **wiki-search-results**: Search Azure DevOps wiki pages with formatted results
|
|
203
|
+
10. **wiki-page-content**: Get a formatted wiki page with navigation context
|
|
204
|
+
11. **work-item-summary**: Get a comprehensive summary of a work item with comments
|
|
205
|
+
12. **work-items-query-report**: Execute a WIQL query and get formatted results
|
|
289
206
|
|
|
290
207
|
## Prompt Examples
|
|
291
208
|
|
|
@@ -963,6 +880,49 @@ AZUREDEVOPS_ENABLE_WIKI_WRITE=true
|
|
|
963
880
|
# PAT with: vso.wiki (read/write), vso.work_write (read/write), vso.search (read)
|
|
964
881
|
```
|
|
965
882
|
|
|
883
|
+
## Development & Release Strategy
|
|
884
|
+
|
|
885
|
+
This project follows a structured branching strategy for development and releases:
|
|
886
|
+
|
|
887
|
+
### Branch Strategy
|
|
888
|
+
|
|
889
|
+
- **`feature/*` branches**: For active development of new features
|
|
890
|
+
- Create feature branches off `main`
|
|
891
|
+
- Develop and test changes locally
|
|
892
|
+
- Do NOT publish to npm from feature branches
|
|
893
|
+
|
|
894
|
+
- **`release/*` branches**: For testing versions before release
|
|
895
|
+
- Used to test and validate changes before merging to main
|
|
896
|
+
- Do NOT publish to npm from release branches
|
|
897
|
+
- Example: `release/1.0`, `release/2.0`
|
|
898
|
+
|
|
899
|
+
- **`main` branch**: Production-ready code
|
|
900
|
+
- **ONLY** publish to npm when main branch is updated
|
|
901
|
+
- Merge feature/release branches to main when ready
|
|
902
|
+
- Publishing workflow:
|
|
903
|
+
1. Merge changes to `main`
|
|
904
|
+
2. Update version: `npm version patch|minor|major`
|
|
905
|
+
3. Publish: `npm publish`
|
|
906
|
+
4. Push to GitHub: `git push && git push --tags`
|
|
907
|
+
|
|
908
|
+
### Local Development Setup
|
|
909
|
+
|
|
910
|
+
For local testing during development (feature/release branches):
|
|
911
|
+
|
|
912
|
+
```json
|
|
913
|
+
{
|
|
914
|
+
"mcpServers": {
|
|
915
|
+
"mcp-consultant-tools-dev": {
|
|
916
|
+
"command": "node",
|
|
917
|
+
"args": ["/absolute/path/to/mcp-consultant-tools/build/index.js"],
|
|
918
|
+
"env": { ... }
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
This allows you to test changes locally without publishing to npm.
|
|
925
|
+
|
|
966
926
|
## License
|
|
967
927
|
|
|
968
928
|
MIT
|
package/build/index.js
CHANGED
|
@@ -1183,155 +1183,6 @@ server.tool("query-records", "Query records using an OData filter expression", {
|
|
|
1183
1183
|
};
|
|
1184
1184
|
}
|
|
1185
1185
|
});
|
|
1186
|
-
// PowerPlatform MCP Prompts
|
|
1187
|
-
server.tool("use-powerplatform-prompt", "Use a predefined prompt template for PowerPlatform entities", {
|
|
1188
|
-
promptType: z.enum([
|
|
1189
|
-
"ENTITY_OVERVIEW",
|
|
1190
|
-
"ATTRIBUTE_DETAILS",
|
|
1191
|
-
"QUERY_TEMPLATE",
|
|
1192
|
-
"RELATIONSHIP_MAP"
|
|
1193
|
-
]).describe("The type of prompt template to use"),
|
|
1194
|
-
entityName: z.string().describe("The logical name of the entity"),
|
|
1195
|
-
attributeName: z.string().optional().describe("The logical name of the attribute (required for ATTRIBUTE_DETAILS prompt)"),
|
|
1196
|
-
}, async ({ promptType, entityName, attributeName }) => {
|
|
1197
|
-
try {
|
|
1198
|
-
// Get or initialize PowerPlatformService
|
|
1199
|
-
const service = getPowerPlatformService();
|
|
1200
|
-
let promptContent = "";
|
|
1201
|
-
let replacements = {};
|
|
1202
|
-
switch (promptType) {
|
|
1203
|
-
case "ENTITY_OVERVIEW": {
|
|
1204
|
-
// Get entity metadata and key attributes
|
|
1205
|
-
const [metadata, attributes] = await Promise.all([
|
|
1206
|
-
service.getEntityMetadata(entityName),
|
|
1207
|
-
service.getEntityAttributes(entityName)
|
|
1208
|
-
]);
|
|
1209
|
-
// Format entity details
|
|
1210
|
-
const entityDetails = `- Display Name: ${metadata.DisplayName?.UserLocalizedLabel?.Label || entityName}\n` +
|
|
1211
|
-
`- Schema Name: ${metadata.SchemaName}\n` +
|
|
1212
|
-
`- Description: ${metadata.Description?.UserLocalizedLabel?.Label || 'No description'}\n` +
|
|
1213
|
-
`- Primary Key: ${metadata.PrimaryIdAttribute}\n` +
|
|
1214
|
-
`- Primary Name: ${metadata.PrimaryNameAttribute}`;
|
|
1215
|
-
// Get key attributes
|
|
1216
|
-
const keyAttributes = attributes.value
|
|
1217
|
-
//.slice(0, 10) // Limit to first 10 important attributes
|
|
1218
|
-
.map((attr) => {
|
|
1219
|
-
const attrType = attr["@odata.type"] || attr.odata?.type || "Unknown type";
|
|
1220
|
-
return `- ${attr.LogicalName}: ${attrType}`;
|
|
1221
|
-
})
|
|
1222
|
-
.join('\n');
|
|
1223
|
-
// Get relationships summary
|
|
1224
|
-
const relationships = await service.getEntityRelationships(entityName);
|
|
1225
|
-
const oneToManyCount = relationships.oneToMany.value.length;
|
|
1226
|
-
const manyToManyCount = relationships.manyToMany.value.length;
|
|
1227
|
-
const relationshipsSummary = `- One-to-Many Relationships: ${oneToManyCount}\n` +
|
|
1228
|
-
`- Many-to-Many Relationships: ${manyToManyCount}`;
|
|
1229
|
-
promptContent = powerPlatformPrompts.ENTITY_OVERVIEW(entityName);
|
|
1230
|
-
replacements = {
|
|
1231
|
-
'{{entity_details}}': entityDetails,
|
|
1232
|
-
'{{key_attributes}}': keyAttributes,
|
|
1233
|
-
'{{relationships}}': relationshipsSummary
|
|
1234
|
-
};
|
|
1235
|
-
break;
|
|
1236
|
-
}
|
|
1237
|
-
case "ATTRIBUTE_DETAILS": {
|
|
1238
|
-
if (!attributeName) {
|
|
1239
|
-
throw new Error("attributeName is required for ATTRIBUTE_DETAILS prompt");
|
|
1240
|
-
}
|
|
1241
|
-
// Get attribute details
|
|
1242
|
-
const attribute = await service.getEntityAttribute(entityName, attributeName);
|
|
1243
|
-
// Format attribute details
|
|
1244
|
-
const attrDetails = `- Display Name: ${attribute.DisplayName?.UserLocalizedLabel?.Label || attributeName}\n` +
|
|
1245
|
-
`- Description: ${attribute.Description?.UserLocalizedLabel?.Label || 'No description'}\n` +
|
|
1246
|
-
`- Type: ${attribute.AttributeType}\n` +
|
|
1247
|
-
`- Format: ${attribute.Format || 'N/A'}\n` +
|
|
1248
|
-
`- Is Required: ${attribute.RequiredLevel?.Value || 'No'}\n` +
|
|
1249
|
-
`- Is Searchable: ${attribute.IsValidForAdvancedFind || false}`;
|
|
1250
|
-
promptContent = powerPlatformPrompts.ATTRIBUTE_DETAILS(entityName, attributeName);
|
|
1251
|
-
replacements = {
|
|
1252
|
-
'{{attribute_details}}': attrDetails,
|
|
1253
|
-
'{{data_type}}': attribute.AttributeType,
|
|
1254
|
-
'{{required}}': attribute.RequiredLevel?.Value || 'No',
|
|
1255
|
-
'{{max_length}}': attribute.MaxLength || 'N/A'
|
|
1256
|
-
};
|
|
1257
|
-
break;
|
|
1258
|
-
}
|
|
1259
|
-
case "QUERY_TEMPLATE": {
|
|
1260
|
-
// Get entity metadata to determine plural name
|
|
1261
|
-
const metadata = await service.getEntityMetadata(entityName);
|
|
1262
|
-
const entityNamePlural = metadata.EntitySetName;
|
|
1263
|
-
// Get a few important fields for the select example
|
|
1264
|
-
const attributes = await service.getEntityAttributes(entityName);
|
|
1265
|
-
const selectFields = attributes.value
|
|
1266
|
-
.slice(0, 5) // Just take first 5 for example
|
|
1267
|
-
.map((attr) => attr.LogicalName)
|
|
1268
|
-
.join(',');
|
|
1269
|
-
promptContent = powerPlatformPrompts.QUERY_TEMPLATE(entityNamePlural);
|
|
1270
|
-
replacements = {
|
|
1271
|
-
'{{selected_fields}}': selectFields,
|
|
1272
|
-
'{{filter_conditions}}': `${metadata.PrimaryNameAttribute} eq 'Example'`,
|
|
1273
|
-
'{{order_by}}': `${metadata.PrimaryNameAttribute} asc`,
|
|
1274
|
-
'{{max_records}}': '50'
|
|
1275
|
-
};
|
|
1276
|
-
break;
|
|
1277
|
-
}
|
|
1278
|
-
case "RELATIONSHIP_MAP": {
|
|
1279
|
-
// Get relationships
|
|
1280
|
-
const relationships = await service.getEntityRelationships(entityName);
|
|
1281
|
-
// Format one-to-many relationships where this entity is primary
|
|
1282
|
-
const oneToManyPrimary = relationships.oneToMany.value
|
|
1283
|
-
.filter((rel) => rel.ReferencingEntity !== entityName)
|
|
1284
|
-
//.slice(0, 10) // Limit to 10 for readability
|
|
1285
|
-
.map((rel) => `- ${rel.SchemaName}: ${entityName} (1) → ${rel.ReferencingEntity} (N)`)
|
|
1286
|
-
.join('\n');
|
|
1287
|
-
// Format one-to-many relationships where this entity is related
|
|
1288
|
-
const oneToManyRelated = relationships.oneToMany.value
|
|
1289
|
-
.filter((rel) => rel.ReferencingEntity === entityName)
|
|
1290
|
-
//.slice(0, 10) // Limit to 10 for readability
|
|
1291
|
-
.map((rel) => `- ${rel.SchemaName}: ${rel.ReferencedEntity} (1) → ${entityName} (N)`)
|
|
1292
|
-
.join('\n');
|
|
1293
|
-
// Format many-to-many relationships
|
|
1294
|
-
const manyToMany = relationships.manyToMany.value
|
|
1295
|
-
//.slice(0, 10) // Limit to 10 for readability
|
|
1296
|
-
.map((rel) => {
|
|
1297
|
-
const otherEntity = rel.Entity1LogicalName === entityName ? rel.Entity2LogicalName : rel.Entity1LogicalName;
|
|
1298
|
-
return `- ${rel.SchemaName}: ${entityName} (N) ↔ ${otherEntity} (N)`;
|
|
1299
|
-
})
|
|
1300
|
-
.join('\n');
|
|
1301
|
-
promptContent = powerPlatformPrompts.RELATIONSHIP_MAP(entityName);
|
|
1302
|
-
replacements = {
|
|
1303
|
-
'{{one_to_many_primary}}': oneToManyPrimary || 'None found',
|
|
1304
|
-
'{{one_to_many_related}}': oneToManyRelated || 'None found',
|
|
1305
|
-
'{{many_to_many}}': manyToMany || 'None found'
|
|
1306
|
-
};
|
|
1307
|
-
break;
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
// Replace all placeholders in the template
|
|
1311
|
-
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
1312
|
-
promptContent = promptContent.replace(placeholder, value);
|
|
1313
|
-
}
|
|
1314
|
-
return {
|
|
1315
|
-
content: [
|
|
1316
|
-
{
|
|
1317
|
-
type: "text",
|
|
1318
|
-
text: promptContent,
|
|
1319
|
-
},
|
|
1320
|
-
],
|
|
1321
|
-
};
|
|
1322
|
-
}
|
|
1323
|
-
catch (error) {
|
|
1324
|
-
console.error("Error using PowerPlatform prompt:", error);
|
|
1325
|
-
return {
|
|
1326
|
-
content: [
|
|
1327
|
-
{
|
|
1328
|
-
type: "text",
|
|
1329
|
-
text: `Failed to use PowerPlatform prompt: ${error.message}`,
|
|
1330
|
-
},
|
|
1331
|
-
],
|
|
1332
|
-
};
|
|
1333
|
-
}
|
|
1334
|
-
});
|
|
1335
1186
|
// Plugin Assemblies List Tool
|
|
1336
1187
|
server.tool("get-plugin-assemblies", "Get a list of all plugin assemblies in the environment", {
|
|
1337
1188
|
includeManaged: z.boolean().optional().describe("Include managed assemblies (default: false)"),
|
|
@@ -1911,7 +1762,11 @@ server.tool("add-work-item-comment", "Add a comment to a work item in Azure DevO
|
|
|
1911
1762
|
server.tool("update-work-item", "Update a work item in Azure DevOps using JSON Patch operations (requires AZUREDEVOPS_ENABLE_WORK_ITEM_WRITE=true)", {
|
|
1912
1763
|
project: z.string().describe("The project name"),
|
|
1913
1764
|
workItemId: z.number().describe("The work item ID"),
|
|
1914
|
-
patchOperations: z.array(z.
|
|
1765
|
+
patchOperations: z.array(z.object({
|
|
1766
|
+
op: z.string().describe("The operation type (e.g., 'add', 'replace', 'remove')"),
|
|
1767
|
+
path: z.string().describe("The field path (e.g., '/fields/System.State')"),
|
|
1768
|
+
value: z.any().optional().describe("The value to set (not required for 'remove' operation)")
|
|
1769
|
+
})).describe("Array of JSON Patch operations"),
|
|
1915
1770
|
}, async ({ project, workItemId, patchOperations }) => {
|
|
1916
1771
|
try {
|
|
1917
1772
|
const service = getAzureDevOpsService();
|