Skip to content

5.6-b Write tools, non-destructive (phase 2) #7700

Description

@andypalmi

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.

Scopes to allow-list + access-tag (#7445): application:device-group:create (write), application:device-group:update (write), application:device-group:membership:update (write).

Tool definitions (description + zod inputSchema):

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    storyA user-oriented description of a feature

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions