5.6-b Write tools, non-destructive (phase 2)
- Dominant language
- JavaScript
- Stars
- 400
- Forks
- 89
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 149
Description
**Parent:** #7675 (5.6 Device groups (fleet))
**Tool file:** new `forge/ee/lib/mcp/tools/deviceGroups.js`
`readOnlyHint: false`, `destructiveHint: false`. Creation, edits, membership changes, and settings are distinct endpoints and scopes, so they stay separate tools.
| Tool | Endpoint | Scope | Annotation |
|---|---|---|---|
| `platform_create_device_group` | `POST /applications/:applicationId/device-groups` | `application:device-group:create` | write |
| `platform_update_device_group` | `PUT /applications/:applicationId/device-groups/:groupId` | `application:device-group:update` | write |
| `platform_update_device_group_membership` | `PATCH /applications/:applicationId/device-groups/:groupId` | `application:device-group:membership:update` | write |
| `platform_update_device_group_settings` | `PUT /applications/:applicationId/device-groups/:groupId/settings` | `application:device-group:update` | write |
**Design notes:**
- All routes require the `deviceGroups` feature (404 otherwise). Surface as a descriptive "device groups not enabled for this team" error.
- `update_device_group` accepts `name`, `description`, and `targetSnapshotId` (string or null) - setting `targetSnapshotId` is how a group's deployed snapshot is pinned/cleared.
- `PUT /:groupId/settings` carries a Member-only `{ env }` field restriction in the handler, but its scope is `application:device-group:update` (Owner), so under standard team RBAC only Owners reach it and they may send the full settings body (the declared schema only names `env`). The Member-only branch is reachable solely via app-specific granted permissions, not ordinary roles.
**Tool definitions (description + zod inputSchema):**
```js
platform_create_device_group: {
description: 'Create a device group in an application.',
inputSchema: z.object({
applicationId: z.string().describe('Application hashid to create the group in'),
name: z.string().describe('Name for the new device group (required)'),
description: z.string().optional().describe('Optional description for the group')
})
}
platform_update_device_group: {
description: 'Update a device group. Setting targetSnapshotId pins the group deployed snapshot; passing null clears it.',
inputSchema: z.object({
applicationId: z.string().describe('Application hashid the group belongs to'),
groupId: z.string().describe('Device group hashid to update'),
name: z.string().optional().describe('New group name'),
description: z.string().optional().describe('New group description'),
targetSnapshotId: z.string().nullable().optional().describe('Snapshot hashid to pin as the group target, or null to clear it')
})
}
platform_update_device_group_membership: {
description: 'Change the membership of a device group. Combine add/remove for incremental changes, or use set to replace the entire membership.',
inputSchema: z.object({
applicationId: z.string().describe('Application hashid the group belongs to'),
groupId: z.string().describe('Device group hashid whose membership to change'),
add: z.array(z.string()).optional().describe('Device hashids to add to the group'),
remove: z.array(z.string()).optional().describe('Device hashids to remove from the group'),
set: z.array(z.string()).optional().describe('Device hashids to set as the exact group membership')
})
}
platform_update_device_group_settings: {
description: 'Update a device group settings. The declared schema names only env; under standard team RBAC only Owners can update device group settings, and only Owners may send settings fields other than env.',
inputSchema: z.object({
applicationId: z.string().describe('Application hashid the group belongs to'),
groupId: z.string().describe('Device group hashid whose settings to update'),
env: z.array(z.record(z.any())).optional().describe('Environment variable objects for the group')
})
}
```
**Tests:**
- Write tools rejected for read-only PAT.
- Feature-disabled team returns the descriptive gate error.
- `update_device_group_settings` write is accepted for an Owner PAT.
---
Contributor guide
Research direction
Start with the new forge/ee/lib/mcp/tools/deviceGroups.js file and trace the four specified endpoints, scopes, annotations, and deviceGroups feature gate. Add the schemas and descriptive disabled-feature handling, then run the listed tests for read-only PAT rejection, feature-disabled teams, and Owner PAT settings writes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100