# Tool Discovery & Visibility Logic (MCP server + CLI)

This document describes how XcodeBuildMCP discovers workflows/tools and decides which ones are visible in:

- the **MCP server** (`xcodebuildmcp mcp`), and
- the **CLI** (`node build/cli.js` / `xcodebuildmcp ...`).

It also documents the current and intended **visibility filtering** behavior (post workflow-selection filtering).

## Terminology

- **Workflow**: a directory under `src/mcp/tools/<workflow>/` containing an `index.ts` with workflow metadata and tool modules.
- **Tool**: a `PluginMeta` exported from a workflow module with `name`, `schema`, and `handler`.
- **Workflow selection**: picking which workflows are active (coarse-grained inclusion).
- **Visibility filtering**: hiding specific tools even if their workflow is enabled (fine-grained exclusion).
- **Dynamic tools**: tools registered at runtime that do not come from static workflows (e.g. proxied Xcode Tools).

## Where workflows/tools come from (source of truth)

Workflows are discovered via generated loaders in `src/core/generated-plugins.ts` (the `WORKFLOW_LOADERS` map). At runtime, `loadWorkflowGroups()` imports each workflow module via these loaders and collects tools from it (`src/core/plugin-registry.ts`).

Key properties of this design:

- Workflows are “discoverable” by enumerating `Object.keys(WORKFLOW_LOADERS)`.
- Tools within a workflow are whatever `index.ts` exports (excluding `workflow` itself).
- A single tool name can appear in multiple workflows (re-exports). This matters for workflow management and hiding.

## MCP server: registration pipeline

At MCP server startup:

1) Runtime config is loaded (`bootstrapRuntime` → `initConfigStore`) from:
   - config file (project config),
   - env (`XCODEBUILDMCP_*`),
   - explicit overrides.

2) Enabled workflows are taken from config (`enabledWorkflows`).

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

4) Workflow selection uses `selectWorkflowsForMcp(...)` (`src/visibility/exposure.ts`) which:
   - includes auto-include workflows whose predicates pass (e.g., `session-management` with no predicates is always included),
   - includes explicitly requested workflows from config,
   - defaults to `defaultEnabled: true` workflows (e.g., `simulator`) when `enabledWorkflows` is empty,
   - filters all selected workflows by availability + predicates.

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

6) If visible, the tool is registered via `server.registerTool(...)`.

### Runtime workflow management (MCP)

The `manage-workflows` tool updates the enabled workflow list at runtime and re-applies workflow selection (`src/mcp/tools/workflow-discovery/manage_workflows.ts` → `applyWorkflowSelection(...)`).

Important nuance:

- Because tools can be re-exported across workflows, disabling one workflow may not remove a tool if another enabled workflow still provides that same tool name.
- Visibility filtering operates on the tool name (and workflow name) at registration time; it is layered after workflow selection.

## CLI: discovery and help output

The CLI has two related but distinct concepts:

1) **Command registration / `--help` tree** (yargs commands)
2) **Tool listing** (`xcodebuildmcp tools`) which is driven by a manifest

### CLI command registration (yargs)

CLI mode builds a tool catalog using `buildCliToolCatalog()` which enables **all workflows** returned by `listWorkflowDirectoryNames()` except `session-management` and `workflow-discovery` (`src/cli/cli-tool-catalog.ts`).

The catalog is built via `buildToolCatalog(...)` (`src/runtime/tool-catalog.ts`), which:

- loads workflow groups via `loadWorkflowGroups()`,
- resolves selected workflows (as above),
- applies `shouldExposeTool(...)` as a per-tool visibility filter,
- generates CLI names and disambiguates collisions.

Yargs then registers workflow command groups and per-tool subcommands from the catalog (`src/cli/register-tool-commands.ts`).

Additionally, the CLI registers workflow command groups from workflow metadata even if there are currently zero visible tools in that workflow (so the workflow still appears in `--help` output).

### CLI `tools` command (manifest-driven)

`xcodebuildmcp tools` reads `build/tools-manifest.json` (`src/cli/commands/tools.ts`) which is generated by `npm run generate:tools-manifest` (invoked by `npm run build:tsup`).

Key implications:

- The manifest is a **static analysis** snapshot (canonical source for docs/CLI listing).
- Dynamic runtime tools (see below) are **not** represented in the manifest.

## Dynamic tools: Xcode Tools via `xcrun mcpbridge`

When the `xcode-ide` workflow is enabled, XcodeBuildMCP can proxy Xcode’s IDE tool service through `xcrun mcpbridge` and register proxied tools at runtime.

Properties:

- Proxied tools are registered dynamically and prefixed as `xcode_tools_<RemoteToolName>` (see `src/integrations/xcode-tools-bridge/registry.ts`).
- Proxied tools are not part of any static workflow and are not present in `build/tools-manifest.json`.
- Proxied tool registration can change over time if Xcode’s tool catalog changes (the bridge supports `tools/listChanged`).

## Visibility filtering (post-selection hiding)

### Current behavior (implemented)

`shouldExposeTool(...)` is the single, shared visibility gate for:

- MCP server tool registration (`src/utils/tool-registry.ts`)
- CLI catalog building (`src/runtime/tool-catalog.ts`)

Currently it is used to hide Xcode IDE bridge **debug** tools unless debugging is enabled:

- `xcode_tools_bridge_status`
- `xcode_tools_bridge_sync`
- `xcode_tools_bridge_disconnect`

These tools are gated behind `debug: true` / `XCODEBUILDMCP_DEBUG=true` (`src/utils/tool-visibility.ts`).

### Intended behavior (documented policy)

We also want a broader “Xcode agent mode” visibility filter where specific XcodeBuildMCP tools are hidden when:

- `runningUnderXcode === true`, AND
- Xcode Tools MCP is enabled/available

This is documented in `docs/dev/XCODE_IDE_TOOL_CONFLICTS.md`.

Design principle:

- Workflow selection stays the **primary** “what areas are enabled” control.
- Visibility filtering is a **secondary** control to reduce confusion/duplication and align behavior with the environment (e.g. “inside Xcode, builds/tests should run inside Xcode”).

## Layering summary (what wins)

1) **Workflow selection** decides which workflows are in play.
2) **Visibility filtering** can hide individual tools even within enabled workflows.
3) **Dynamic tools** may appear even if there are no static tools in a workflow (e.g. proxied `xcode_tools_*`).

