5.13-b Write tools, non-destructive (phase 2)
- Dominant language
- JavaScript
- Stars
- 400
- Forks
- 89
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 149
Description
**Parent:** #7682 (5.13 Broker and MQTT (special review))
**Tool file:** new `forge/ee/lib/mcp/tools/broker.js`
`readOnlyHint: false`, `destructiveHint: false`. **Contingent on a product decision to allow broker mutation over MCP.** None of these mint credentials, so #7513 does not block them. Sibling broker lifecycle transitions are consolidated into a single action tool; topic create/update touch broker state but not credentials.
| Tool | Endpoint(s) | Scope | Annotation |
|---|---|---|---|
| `platform_broker_lifecycle_action` (`action`: `start`\|`stop`\|`suspend`) | broker lifecycle routes | `broker:credentials:edit` | write |
| `platform_create_broker_topic` | `POST /teams/:teamId/brokers/:brokerId/topics` | `broker:topics:write` | write |
| `platform_update_broker_topic` | `PUT /teams/:teamId/brokers/:brokerId/topics/:topicId` | `broker:topics:write` | write |
**Design notes:**
- Only the topic **create** route (`POST /topics`) is dual-gated (agent/broker token scope OR user `broker:topics:write`). The **update** route (`PUT /topics/:topicId`) uses a plain `needsPermission('broker:topics:write')` and is not dual-gated; its path is a single `:topicId` param, not a wildcard. The handler only updates `metadata`.
- Broker lifecycle (`start`/`stop`/`suspend`) maps to `PUT /brokers/:brokerId/start|stop|suspend`; it touches broker state but does not mint credentials, so it is not in the #7513 class; it remains contingent on the broker-mutation decision.
- The whole surface is gated by the enterprise license tier and the per-team `teamBroker` feature flag.
**Tool definitions (description + zod inputSchema):**
```js
platform_broker_lifecycle_action: {
description: 'Applies a lifecycle transition (start, stop, or suspend) to the broker agent.',
inputSchema: z.object({
teamId: z.string().describe('team hashid'),
brokerId: z.string().describe("broker id: either the literal 'team-broker' or a 3rd-party broker hashid"),
action: z.enum(['start', 'stop', 'suspend']).describe('lifecycle transition to apply to the broker agent')
})
},
platform_create_broker_topic: {
description: 'Creates one or more topics for a broker. Accepts a single topic object instead of an array.',
inputSchema: z.object({
teamId: z.string().describe('team hashid'),
brokerId: z.string().describe("broker id: either the literal 'team-broker' or a 3rd-party broker hashid"),
topics: z.array(z.object({
topic: z.string().describe('MQTT topic string'),
type: z.any().optional().describe('inferred payload schema/type; stored as inferredSchema'),
metadata: z.record(z.any()).optional().describe('arbitrary topic metadata (e.g. description, schema)')
})).describe('Topics to store')
})
},
platform_update_broker_topic: {
description: 'Updates a broker topic. Only the topic metadata is updated.',
inputSchema: z.object({
teamId: z.string().describe('team hashid'),
brokerId: z.string().describe("broker id: either the literal 'team-broker' or a 3rd-party broker hashid"),
topicId: z.string().describe('topic hashid'),
metadata: z.record(z.any()).describe('replacement topic metadata')
})
}
```
**Tests (only if writes approved):**
- The action tool routes each enum value to the correct lifecycle route.
- Read-only PAT rejected for every tool here.
- Feature-disabled team returns the descriptive gate error.
---
Contributor guide
Research direction
Start with the product decision in parent issue #7682, then inspect forge/ee/lib/mcp/tools/broker.js and the listed broker lifecycle and topic endpoints. Verify the enterprise license and teamBroker gates, then add the specified tools only if writes are approved. Run tests covering lifecycle routing, read-only PAT rejection, and the feature-disabled error.
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
- Mostly clear
- Newbie friendliness
- 45/100