Skip to content

Commit da74a21

Browse files
committed
Refactor tool system to use YAML manifests and named exports
Migrate all tools from default export objects to named schema handler exports. Add annotations metadata to YAML manifests as single source of truth for tool metadata. Introduce predicates (runningUnderXcodeAgent, requiresXcodeTools) for conditional tool visibility. Remove mandatory workflow selection concept and simplify workflow resolution logic.
1 parent 7bba878 commit da74a21

235 files changed

Lines changed: 1992 additions & 2882 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/dev/MANIFEST_FORMAT.md

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ predicates: string[] # Predicate names for visibility filtering (default: [])
6161
routing: # Daemon routing hints
6262
stateful: boolean # Tool maintains state (default: false)
6363
daemonAffinity: enum # 'preferred' or 'required' (optional)
64+
annotations: # MCP tool annotations (hints for clients)
65+
title: string # Human-readable title (optional)
66+
readOnlyHint: boolean # Tool only reads data (optional)
67+
destructiveHint: boolean # Tool may modify/delete data (optional)
68+
idempotentHint: boolean # Safe to retry (optional)
69+
openWorldHint: boolean # May access external resources (optional)
6470
```
6571
6672
### Example: Basic Tool
@@ -79,6 +85,9 @@ predicates: []
7985
routing:
8086
stateful: false
8187
daemonAffinity: preferred
88+
annotations:
89+
title: "List Simulators"
90+
readOnlyHint: true
8291
```
8392
8493
### Example: Tool with Predicates
@@ -136,7 +145,6 @@ availability: # Per-runtime availability flags
136145
daemon: boolean # Available via daemon (default: true)
137146
selection: # MCP selection rules
138147
mcp:
139-
mandatory: boolean # Always included, cannot be disabled (default: false)
140148
defaultEnabled: boolean # Enabled when config.enabledWorkflows is empty (default: false)
141149
autoInclude: boolean # Include when predicates pass, even if not requested (default: false)
142150
predicates: string[] # Predicate names for visibility filtering (default: [])
@@ -154,7 +162,6 @@ availability:
154162
daemon: true
155163
selection:
156164
mcp:
157-
mandatory: false
158165
defaultEnabled: true # Enabled by default
159166
autoInclude: false
160167
predicates: []
@@ -179,7 +186,6 @@ availability:
179186
daemon: true
180187
selection:
181188
mcp:
182-
mandatory: false
183189
defaultEnabled: false
184190
autoInclude: true # Auto-included when predicates pass
185191
predicates:
@@ -200,7 +206,6 @@ availability:
200206
daemon: false
201207
selection:
202208
mcp:
203-
mandatory: false
204209
defaultEnabled: false
205210
autoInclude: true
206211
predicates:
@@ -226,6 +231,11 @@ tools:
226231
| `predicates` | string[] | No | `[]` | Visibility predicates (all must pass) |
227232
| `routing.stateful` | boolean | No | `false` | Tool maintains state |
228233
| `routing.daemonAffinity` | enum | No | - | `'preferred'` or `'required'` |
234+
| `annotations.title` | string | No | - | Human-readable title |
235+
| `annotations.readOnlyHint` | boolean | No | - | Tool only reads data |
236+
| `annotations.destructiveHint` | boolean | No | - | Tool may modify/delete data |
237+
| `annotations.idempotentHint` | boolean | No | - | Safe to retry |
238+
| `annotations.openWorldHint` | boolean | No | - | May access external resources |
229239

230240
### Workflow Fields
231241

@@ -238,7 +248,6 @@ tools:
238248
| `availability.mcp` | boolean | No | `true` | Available via MCP |
239249
| `availability.cli` | boolean | No | `true` | Available via CLI |
240250
| `availability.daemon` | boolean | No | `true` | Available via daemon |
241-
| `selection.mcp.mandatory` | boolean | No | `false` | Cannot be disabled |
242251
| `selection.mcp.defaultEnabled` | boolean | No | `false` | Enabled when no workflows configured |
243252
| `selection.mcp.autoInclude` | boolean | No | `false` | Auto-include when predicates pass |
244253
| `predicates` | string[] | No | `[]` | Visibility predicates (all must pass) |
@@ -257,8 +266,10 @@ build/mcp/tools/<category>/<tool_name>.js
257266
```
258267

259268
The module must export either:
260-
1. **Named exports** (preferred): `{ schema, handler, annotations? }`
261-
2. **Legacy default export**: `export default { name, schema, handler, annotations? }`
269+
1. **Named exports** (preferred): `{ schema, handler }`
270+
2. **Legacy default export**: `export default { schema, handler }`
271+
272+
Note: `name`, `description`, and `annotations` are defined in the YAML manifest, not the module.
262273

263274
Example module structure:
264275
```typescript
@@ -273,11 +284,6 @@ export const schema = z.object({
273284
export async function handler(params: z.infer<typeof schema>) {
274285
// Implementation
275286
}
276-
277-
export const annotations = {
278-
title: 'Build for Simulator',
279-
// ...
280-
};
281287
```
282288

283289
## Naming Conventions
@@ -311,6 +317,8 @@ Predicates control visibility based on runtime context. All predicates in the ar
311317
|-----------|-------------|
312318
| `debugEnabled` | Show only when `config.debug` is `true` |
313319
| `experimentalWorkflowDiscoveryEnabled` | Show only when experimental workflow discovery is enabled |
320+
| `runningUnderXcodeAgent` | Show only when running under Xcode's coding agent |
321+
| `requiresXcodeTools` | Show only when Xcode Tools bridge is active |
314322
| `hideWhenXcodeAgentMode` | Hide when running under Xcode agent AND Xcode Tools bridge is active |
315323
| `always` | Always visible (explicit documentation) |
316324
| `never` | Never visible (temporarily disable) |
@@ -346,25 +354,25 @@ export const PREDICATES: Record<string, PredicateFn> = {
346354

347355
For MCP runtime, workflows are selected based on these rules (in order):
348356

349-
1. **Mandatory workflows** (`mandatory: true`) are always included
357+
1. **Auto-include workflows** (`autoInclude: true`) when their predicates pass
350358
2. **Explicitly requested workflows** from `config.enabledWorkflows`
351359
3. **Default workflows** (`defaultEnabled: true`) when `config.enabledWorkflows` is empty
352-
4. **Auto-include workflows** (`autoInclude: true`) when their predicates pass
360+
4. All selected workflows are filtered by availability + predicates
353361

354362
### Selection Examples
355363

356364
```yaml
357-
# Always included regardless of config
365+
# Always included (autoInclude with no predicates = always passes)
358366
selection:
359367
mcp:
360-
mandatory: true
368+
autoInclude: true
361369
362-
# Enabled by default, can be disabled
370+
# Enabled by default when no workflows configured
363371
selection:
364372
mcp:
365373
defaultEnabled: true
366374
367-
# Auto-included when predicates pass (e.g., debug mode)
375+
# Auto-included only when predicates pass (e.g., debug mode)
368376
selection:
369377
mcp:
370378
autoInclude: true
@@ -418,7 +426,7 @@ At startup, tools are registered dynamically from manifests:
418426
419427
2. selectWorkflowsForMcp(workflows, requestedWorkflows, ctx)
420428
└── Filters workflows by availability (mcp: true)
421-
└── Applies selection rules (mandatory, defaultEnabled, autoInclude)
429+
└── Applies selection rules (defaultEnabled, autoInclude)
422430
└── Evaluates predicates against context
423431
424432
3. For each selected workflow:

docs/dev/TOOL_DISCOVERY_LOGIC.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ At MCP server startup:
3838

3939
3) `registerWorkflows(enabledWorkflows)` runs, which calls `applyWorkflowSelection(...)` (`src/utils/tool-registry.ts`).
4040

41-
4) Workflow selection uses `resolveSelectedWorkflows(...)` (`src/utils/workflow-selection.ts`) which:
42-
- always includes `session-management`,
43-
- optionally includes `doctor` when `debug: true`,
44-
- optionally includes `workflow-discovery` when `experimentalWorkflowDiscovery: true`,
45-
- defaults to `simulator` when `enabledWorkflows` is empty.
41+
4) Workflow selection uses `selectWorkflowsForMcp(...)` (`src/visibility/exposure.ts`) which:
42+
- includes auto-include workflows whose predicates pass (e.g., `session-management` with no predicates is always included),
43+
- includes explicitly requested workflows from config,
44+
- defaults to `defaultEnabled: true` workflows (e.g., `simulator`) when `enabledWorkflows` is empty,
45+
- filters all selected workflows by availability + predicates.
4646

4747
5) For each selected workflow, each tool is considered for registration, then filtered by `shouldExposeTool(workflowName, toolName)` (`src/utils/tool-registry.ts`).
4848

manifests/tools/boot_sim.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ predicates: []
1111
routing:
1212
stateful: false
1313
daemonAffinity: preferred
14+
annotations:
15+
title: "Boot Simulator"
16+
destructiveHint: true

manifests/tools/build_device.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ predicates:
1212
routing:
1313
stateful: false
1414
daemonAffinity: preferred
15+
annotations:
16+
title: "Build Device"
17+
destructiveHint: true

manifests/tools/build_macos.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ predicates:
1212
routing:
1313
stateful: false
1414
daemonAffinity: preferred
15+
annotations:
16+
title: "Build macOS"
17+
destructiveHint: true

manifests/tools/build_run_macos.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ predicates:
1212
routing:
1313
stateful: false
1414
daemonAffinity: preferred
15+
annotations:
16+
title: "Build Run macOS"
17+
destructiveHint: true

manifests/tools/build_run_sim.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ predicates:
1212
routing:
1313
stateful: false
1414
daemonAffinity: preferred
15+
annotations:
16+
title: "Build Run Simulator"
17+
destructiveHint: true

manifests/tools/build_sim.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ predicates:
1212
routing:
1313
stateful: false
1414
daemonAffinity: preferred
15+
annotations:
16+
title: "Build Simulator"
17+
destructiveHint: true

manifests/tools/button.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ predicates: []
1111
routing:
1212
stateful: false
1313
daemonAffinity: preferred
14+
annotations:
15+
title: "Hardware Button"
16+
destructiveHint: true

manifests/tools/clean.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ predicates:
1212
routing:
1313
stateful: false
1414
daemonAffinity: preferred
15+
annotations:
16+
title: "Clean"
17+
destructiveHint: true

0 commit comments

Comments
 (0)